使用线程和fork实现归并排序

Implementation of merge sort using threads and fork

问题: 我正在尝试通过以下方式实现合并排序,我有一个 Parent 和两个 children。第一个 child 将自己使用合并排序,第二个 child 将按以下方式实现:创建 2 个线程,第一个将对数组的前半部分进行排序,第二个将排序其余的部分。然后,在调用归并排序之后,他会再次为前半部分创建 2 个线程,为其余部分创建 2 个线程,依此类推,直到我们在基本情况下结束并完成。最后,我想检查第二个 child 比第一个 child.

实现合并排序快多少

我的问题: 我创建了 2 个 child,第一个 child 正在执行排序合并,一切正常。第二个 child - 我只能创建 2 个线程,而不是更多(然后每半个 2 个,依此类推),最后它既不打印数组也不打印完成日期。

这是第二个的代码child:

if((id2 = fork()) == 0 && id1 != 0)
    {
        printf("Child2: \n");
        ans1 = pthread_create ( &thread1 , NULL , mergeSort ,(arr3, (arr_size / 2) - 1 ,arr_size - 1 )) ;
        ans2 = pthread_create ( &thread2 , NULL , mergeSort ,(arr3, 0, (arr_size / 2)-  1 )) ;
        ans3 = pthread_create ( &thread3 , NULL , printArray ,(arr3, arr_size) ) ;
        execl("/bin/date", "date",0);
        if ( ans1 != 0 || ans2 != 0 || ans3 != 0) {
            printf ( " \n can't create threads " ) ;
            exit(0) ;
        }
            pthread_join ( thread1 , NULL ) ;
            pthread_join ( thread2 , NULL ) ;
            pthread_join ( thread3 , NULL ) ;

    }

我使用的是 UNIX,编译时:

gcc -lpthread prog.c

用于执行:

./a.out

这是完整的代码:

/* C program for Merge Sort */
#include<stdlib.h>
#include<stdio.h>
#include <pthread.h>

#define N 100

// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
void merge(int arr[], int l, int m, int r)
{
    int i, j, k;
    int n1 = m - l + 1;
    int n2 =  r - m;

    /* create temp arrays */
    int L[n1], R[n2];

    /* Copy data to temp arrays L[] and R[] */
    for (i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (j = 0; j < n2; j++)
        R[j] = arr[m + 1+ j];

    /* Merge the temp arrays back into arr[l..r]*/
    i = 0; // Initial index of first subarray
    j = 0; // Initial index of second subarray
    k = l; // Initial index of merged subarray
    while (i < n1 && j < n2)
    {
        if (L[i] <= R[j])
        {
            arr[k] = L[i];
            i++;
        }
        else
        {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    /* Copy the remaining elements of L[], if there
       are any */
    while (i < n1)
    {
        arr[k] = L[i];
        i++;
        k++;
    }

    /* Copy the remaining elements of R[], if there
       are any */
    while (j < n2)
    {
        arr[k] = R[j];
        j++;
        k++;
    }
}

/* l is for left index and r is right index of the
   sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
    if (l < r)
    {
        // Same as (l+r)/2, but avoids overflow for
        // large l and h
        int m = l+(r-l)/2;

        // Sort first and second halves
        mergeSort(arr, l, m);
        mergeSort(arr, m+1, r);

        merge(arr, l, m, r);
    }
}

/* UTILITY FUNCTIONS */
/* Function to print an array */
void printArray(int A[], int size)
{
    int i;
    for (i=0; i < size; i++)
        printf("%d ", A[i]);
    printf("\n");
}

/* Driver program to test above functions */
int main()
{
    int min = -1000, max = 1000;
    int arr[10], arr2[10], arr3[10];
    int i,r;
    int arr_size = sizeof(arr)/sizeof(arr[0]);
    int id1,id2;
    //Threads init
    pthread_t thread1 , thread2, thread3;
    int ans1, ans2, ans3;


    for( i = 0; i < arr_size; i++){
        r = rand() % (max - min + 1);
        arr[i] = r;
        arr2[i] = r;
        arr3[i] = r;
    }
    //printf("Before: \n");

    if((id1 = fork()) == 0)
    {
        printf("Child1: \n");
        mergeSort(arr2, 0, arr_size - 1);
        printArray(arr2, arr_size);
        execl("/bin/date", "date",0);
    }

    if((id2 = fork()) == 0 && id1 != 0)
    {
        printf("Child2: \n");
        ans1 = pthread_create ( &thread1 , NULL , mergeSort ,(arr3, (arr_size / 2) - 1 ,arr_size - 1 )) ;
        ans2 = pthread_create ( &thread2 , NULL , mergeSort ,(arr3, 0, (arr_size / 2)-  1 )) ;
        ans3 = pthread_create ( &thread3 , NULL , printArray ,(arr3, arr_size) ) ;
        execl("/bin/date", "date",0);
        if ( ans1 != 0 || ans2 != 0 || ans3 != 0) {
            printf ( " \n can't create threads " ) ;
            exit(0) ;
        }
            pthread_join ( thread1 , NULL ) ;
            pthread_join ( thread2 , NULL ) ;
            pthread_join ( thread3 , NULL ) ;

    }
    wait();
    if(id1 != 0 && id2 != 0){

        printf("Given array is \n");
        printArray(arr, arr_size);
        printf("Father:\n");
        mergeSort(arr, 0, arr_size - 1);
        printArray(arr, arr_size);
        execl("/bin/date", "date",0);
        printf("\nSorted array is \n");
        //printf("After: \n");
    }
    return 0;
}

编辑代码:

   /* C program for Merge Sort */
#include<stdlib.h>
#include<stdio.h>
#include <pthread.h>
#include <time.h>

#define N 100

// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
void merge(int arr[], int l, int m, int r)
{
    int i, j, k;
    int n1 = m - l + 1;
    int n2 =  r - m;

    /* create temp arrays */
    int L[n1], R[n2];

    /* Copy data to temp arrays L[] and R[] */
    for (i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (j = 0; j < n2; j++)
        R[j] = arr[m + 1+ j];

    /* Merge the temp arrays back into arr[l..r]*/
    i = 0; // Initial index of first subarray
    j = 0; // Initial index of second subarray
    k = l; // Initial index of merged subarray
    while (i < n1 && j < n2)
    {
        if (L[i] <= R[j])
        {
            arr[k] = L[i];
            i++;
        }
        else
        {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    /* Copy the remaining elements of L[], if there
       are any */
    while (i < n1)
    {
        arr[k] = L[i];
        i++;
        k++;
    }

    /* Copy the remaining elements of R[], if there
       are any */
    while (j < n2)
    {
        arr[k] = R[j];
        j++;
        k++;
    }
}

/* l is for left index and r is right index of the
   sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
    if (l < r)
    {
        // Same as (l+r)/2, but avoids overflow for
        // large l and h
        int m = l+(r-l)/2;

        // Sort first and second halves
        mergeSort(arr, l, m);
        mergeSort(arr, m+1, r);

        merge(arr, l, m, r);
    }
}

void* mergeSort2(void* args)
{

    int* newArgs = (int*)args;
    int l = newArgs[1];
    int r = newArgs[2];

    pthread_t thread1 , thread2;
    int ans1, ans2;

    if (l < r)
    {
        // Same as (l+r)/2, but avoids overflow for
        // large l and h
        int m = (r+l)/2;
        int newArgs1[3] = {newArgs[0], l, m};
        int newArgs2[3] = {newArgs[0], m+1, r};
        ans1 = pthread_create ( &thread1 , NULL , mergeSort2 ,(void*)newArgs1);
        ans1 = pthread_create ( &thread2 , NULL , mergeSort2 ,(void*)newArgs2);
        pthread_join(thread1,NULL);     
        pthread_join(thread2,NULL);

        merge(newArgs[0], l, m, r);

    }

}

/* UTILITY FUNCTIONS */
/* Function to print an array */
void printArray(int A[], int size)
{
    int i;
    for (i=0; i < size; i++)
        printf("%d ", A[i]);
    printf("\n");
}

static void print_timestamp(void)
{
    time_t now = time(0);
    struct tm *utc = gmtime(&now);
    char iso8601[32];
    strftime(iso8601, sizeof(iso8601), "%Y-%m-%d  %H:%M:%S", utc);
    printf("%s\n", iso8601);
}

/* Driver program to test above functions */
int main()
{
    int min = -1000, max = 1000;
    int arr[10], arr2[10], arr3[10];
    int i,r;
    int arr_size = sizeof(arr)/sizeof(arr[0]);
    int id1,id2;
    int args[3] ={arr3, 0, arr_size - 1};
     struct timeval tvalBefore, tvalAfter;
     struct timeval tvalBefore1, tvalAfter1;
    //Threads init
    pthread_t thread1;
    int ans1;

    srand(time(NULL));

    for( i = 0; i < arr_size; i++){
        r = rand() % (max - min + 1);
        arr[i] = r;
        arr2[i] = r;
        arr3[i] = r;
    }
    //printf("Before: \n");

    if((id1 = fork()) == 0)
    {
     gettimeofday (&tvalBefore, NULL);
    //Operation to do
        printf("Child1: \n");
        mergeSort(arr2, 0, arr_size - 1);
        printArray(arr2, arr_size);
        print_timestamp();
    gettimeofday (&tvalAfter, NULL);

    // Changed format to long int (%ld), changed time calculation

    printf("Time in microseconds for sorting CHILD 1: %ld microseconds\n",
            ((tvalAfter.tv_sec - tvalBefore.tv_sec)*1000000L
           +tvalAfter.tv_usec) - tvalBefore.tv_usec
          ); // Added semicolon
    }

    else if((id2 = fork()) == 0)
    {

        printf("Child2: \n");
        //Start Timer
        gettimeofday (&tvalBefore1, NULL);
        //Operation to do
        ans1 = pthread_create ( &thread1 , NULL , mergeSort2 ,(void*)args);
        pthread_join ( thread1 , NULL ) ;

        print_timestamp();
        gettimeofday (&tvalAfter1, NULL);
        // Changed format to long int (%ld), changed time calculation

         printf("Time in microseconds for sorting CHILD 2: %ld microseconds\n",
            ((tvalAfter1.tv_sec - tvalBefore1.tv_sec)*1000000L
           +tvalAfter1.tv_usec) - tvalBefore1.tv_usec
          ); // Added semicolon
    }

    else{
        wait();
        wait();
         gettimeofday (&tvalBefore, NULL);
        //Operation to do
        printf("Given array is \n");
        printArray(arr, arr_size);
        printf("Father:\n");
        mergeSort(arr, 0, arr_size - 1);
        printArray(arr, arr_size);
        print_timestamp();

        gettimeofday (&tvalAfter, NULL);

    // Changed format to long int (%ld), changed time calculation

    printf("Time in microseconds for sorting Father: %ld microseconds\n",
            ((tvalAfter.tv_sec - tvalBefore.tv_sec)*1000000L
           +tvalAfter.tv_usec) - tvalBefore.tv_usec
          ); // Added semicolon
    }
    return 0;
}

程序因调用 execl()

而停止

你有:

    …
    ans3 = pthread_create ( &thread3 , NULL , printArray ,(arr3, arr_size) ) ;
    execl("/bin/date", "date",0);
    if ( ans1 != 0 || ans2 != 0 || ans3 != 0) {
        …

execl() 将您的进程及其所有线程替换为 date,从而产生其输出并退出。你不能time-stamp那样工作!

您可能需要调用time()或higher-resolution计时机制,然后localtime()gmtime()创建broken-down时间,然后strftime() 根据需要格式化,最后 printf() 或类似的打印结果。这一切都属于一个函数,当然,不在您的代码中。

#include <stdio.h>
#include <time.h>

static void print_timestamp(void)
{
    time_t now = time(0);
    struct tm *utc = gmtime(&now);
    char iso8601[32];
    strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%S", utc);
    printf("%s\n", iso8601);
}

在你有 execl() 的地方,改为调用 print_timestamp()

或者,更简单地说,使用 system() 而不是 execl()

system("/bin/date");

这是一种奇怪的重量级报告时间的方式,但它具有简单的优点。

Sub-second 解决时间

I need to determine the time in milliseconds.

这取决于您的平台,但在 POSIX-ish 系统上您可以使用 clock_gettime() or gettimeofday() 获得 sub-second 计时。

#include <stdio.h>
#include <time.h>
#include <sys/time.h>

static void print_timestamp(void)   // UTC to seconds
{
    time_t now = time(0);
    struct tm *utc = gmtime(&now);
    char iso8601[32];
    strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%S", utc);
    printf("%s\n", iso8601);
}

static void print_utc_ms(void)      // UTC to milliseconds
{
    struct timeval tv;
    gettimeofday(&tv, 0);
    struct tm *utc = gmtime(&tv.tv_sec);
    char iso8601[32];
    strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%S", utc);
    printf("%s.%.3d\n", iso8601, tv.tv_usec / 1000);
}

static void print_local_us(void)    // Local time to microseconds
{
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);     // CLOCK_MONOTONIC has merits too
    struct tm *lmt = localtime(&ts.tv_sec);
    char iso8601[32];
    strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%S", lmt);
    printf("%s.%.6ld\n", iso8601, ts.tv_nsec / 1000L);
}

int main(void)
{
    print_timestamp();
    print_utc_ms();
    print_local_us();
    return 0;
}

示例输出:

2017-05-05T16:04:14
2017-05-05T16:04:14.268
2017-05-05T09:04:14.268975

注意:一旦您修复了代码使其不使用 execl(),可能仍有其他问题需要解决 — 可能还有其他问题需要解决。但解决这个问题是让您的线程 运行 完成的关键步骤。

正在创建工作代码

从问题中获取修改后的代码,对其应用基本 'cleanliness'(确保它在严格的警告选项下干净地编译),该程序似乎可以运行。 'array of int' 传递指针和两个 int 值的方法在 64 位系统上不起作用,因此我创建了一个 struct Sort 来包含这些信息。我还将 'start clock' 和 'stop clock' 调用移动到 gettimeofday() 更靠近被测量的代码(不会在调用代码中打印)。我添加了 macOS Sierra 10.12.4 (GCC 7.1.0) 所需的 headers。该代码还在对任何输入数据进行排序之前打印输入数据。清理工作基本上是 'around' 排序代码;核心排序算法完全没有改变。

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>   // gettimeofday()
#include <unistd.h>     // fork()
#include <sys/wait.h>   // wait()

#define N 100

struct Sort
{
    int *data;
    int  lo;
    int  hi;
};

// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
static
void merge(int arr[], int l, int m, int r)
{
    int i, j, k;
    int n1 = m - l + 1;
    int n2 =  r - m;

    /* create temp arrays */
    int L[n1], R[n2];

    /* Copy data to temp arrays L[] and R[] */
    for (i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];

    /* Merge the temp arrays back into arr[l..r]*/
    i = 0; // Initial index of first subarray
    j = 0; // Initial index of second subarray
    k = l; // Initial index of merged subarray
    while (i < n1 && j < n2)
    {
        if (L[i] <= R[j])
        {
            arr[k] = L[i];
            i++;
        }
        else
        {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    /* Copy the remaining elements of L[], if there
       are any */
    while (i < n1)
    {
        arr[k] = L[i];
        i++;
        k++;
    }

    /* Copy the remaining elements of R[], if there
       are any */
    while (j < n2)
    {
        arr[k] = R[j];
        j++;
        k++;
    }
}

/* l is for left index and r is right index of the
   sub-array of arr to be sorted */
static
void mergeSort(int arr[], int l, int r)
{
    if (l < r)
    {
        // Same as (l+r)/2, but avoids overflow for
        // large l and h
        int m = l + (r - l) / 2;

        // Sort first and second halves
        mergeSort(arr, l, m);
        mergeSort(arr, m + 1, r);

        merge(arr, l, m, r);
    }
}

static
void *mergeSort2(void *args)
{
    struct Sort *newargs = args;
    int *data = newargs->data;
    int l = newargs->lo;
    int r = newargs->hi;

    pthread_t thread1, thread2;
    int ans1, ans2;

    if (l < r)
    {
        int m = (r + l) / 2;
        struct Sort newArgs1 = {data, l, m};
        struct Sort newArgs2 = {data, m + 1, r};
        ans1 = pthread_create(&thread1, NULL, mergeSort2, &newArgs1);
        ans2 = pthread_create(&thread2, NULL, mergeSort2, &newArgs2);
        if (ans1 != 0 || ans2 != 0)
            exit(1);
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);

        merge(data, l, m, r);
    }
    return 0;
}

/* UTILITY FUNCTIONS */
/* Function to print an array */
static
void printArray(int A[], int size)
{
    for (int i = 0; i < size; i++)
        printf("%d ", A[i]);
    printf("\n");
}

static void print_timestamp(void)
{
    time_t now = time(0);
    struct tm *utc = gmtime(&now);
    char iso8601[32];
    strftime(iso8601, sizeof(iso8601), "%Y-%m-%d  %H:%M:%S", utc);
    printf("%s\n", iso8601);
}

/* Driver program to test above functions */
int main(void)
{
    int min = -1000, max = 1000;
    int arr[10], arr2[10], arr3[10];
    int i, r;
    int arr_size = sizeof(arr) / sizeof(arr[0]);
    int id1, id2;
    struct Sort args = { arr3, 0, arr_size - 1};
    struct timeval tvalBefore, tvalAfter;
    struct timeval tvalBefore1, tvalAfter1;
    // Threads init
    pthread_t thread1;
    int ans1;

    srand(time(NULL));

    for (i = 0; i < arr_size; i++)
    {
        r = rand() % (max - min + 1);
        arr[i] = r;
        arr2[i] = r;
        arr3[i] = r;
    }
    printf("Given array is \n");
    printArray(arr, arr_size);
    fflush(stdout);

    if ((id1 = fork()) == 0)
    {
        printf("Child1: \n");
        gettimeofday(&tvalBefore, NULL);
        mergeSort(arr2, 0, arr_size - 1);
        gettimeofday(&tvalAfter, NULL);
        printArray(arr2, arr_size);
        print_timestamp();

        printf("Time in microseconds for sorting CHILD 1: %ld microseconds\n",
               ((tvalAfter.tv_sec - tvalBefore.tv_sec) * 1000000L
                + tvalAfter.tv_usec) - tvalBefore.tv_usec);
    }
    else if ((id2 = fork()) == 0)
    {
        printf("Child2: \n");
        gettimeofday(&tvalBefore1, NULL);
        ans1 = pthread_create(&thread1, NULL, mergeSort2, &args);
        if (ans1 == 0)
            pthread_join( thread1, NULL );
        gettimeofday(&tvalAfter1, NULL);
        print_timestamp();
        printArray(arr3, arr_size);
        printf("Time in microseconds for sorting CHILD 2: %ld microseconds\n",
               ((tvalAfter1.tv_sec - tvalBefore1.tv_sec) * 1000000L
                + tvalAfter1.tv_usec) - tvalBefore1.tv_usec);
    }
    else
    {
        wait(0);
        wait(0);
        printf("Parent:\n");
        gettimeofday(&tvalBefore, NULL);
        mergeSort(arr, 0, arr_size - 1);
        gettimeofday(&tvalAfter, NULL);
        printArray(arr, arr_size);
        print_timestamp();

        printf("Time in microseconds for sorting Parent: %ld microseconds\n",
               ((tvalAfter.tv_sec - tvalBefore.tv_sec) * 1000000L
                + tvalAfter.tv_usec) - tvalBefore.tv_usec);
    }
    return 0;
}

编译(来源ms83.c):

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes -Wold-style-definition ms83.c -o ms83
$

示例运行 1:

Given array is 
574 494 441 870 1121 800 1864 1819 889 242 
Child1: 
242 441 494 574 800 870 889 1121 1819 1864 
2017-05-05  21:31:23
Time in microseconds for sorting CHILD 1: 10 microseconds
Child2: 
2017-05-05  21:31:23
242 441 494 574 800 870 889 1121 1819 1864 
Time in microseconds for sorting CHILD 2: 3260 microseconds
Parent:
242 441 494 574 800 870 889 1121 1819 1864 
2017-05-05  21:31:23
Time in microseconds for sorting Parent: 7 microseconds

示例运行 2:

Given array is 
150 562 748 1685 889 1859 1807 1904 863 1675 
Child1: 
150 562 748 863 889 1675 1685 1807 1859 1904 
2017-05-05  21:31:40
Time in microseconds for sorting CHILD 1: 11 microseconds
Child2: 
2017-05-05  21:31:40
150 562 748 863 889 1675 1685 1807 1859 1904 
Time in microseconds for sorting CHILD 2: 4745 microseconds
Parent:
150 562 748 863 889 1675 1685 1807 1859 1904 
2017-05-05  21:31:40
Time in microseconds for sorting Parent: 7 microseconds

请注意,线程解决方案比 non-threading 代码慢三个数量级。

当我尝试将数组大小从 10 增加到 10,000 时,线程 child 没有完成。这意味着线程创建在某处失败。错误报告是有缺陷的(我是懒惰的)。切换到 500 个条目产生:

Given array is 
1984 1436 713 1349 855 1296 559 1647 567 1153 1156 1395 865 1380 840 1253 714 1396 333 404 538 1468 1381 489 1274 34 697 1484 1742 756 1221 1717 331 532 746 842 1235 1179 1185 1547 1372 1305 138 404 76 762 605 61 1242 1075 1896 203 1173 844 1582 1356 1044 1760 1635 1833 1595 1651 1892 1842 1508 727 357 221 878 967 1665 1783 1927 1655 1110 220 711 371 1785 401 188 1132 1947 1214 5 1414 1065 730 826 807 1155 654 1745 1993 1215 741 1721 1509 604 16 139 804 1773 690 1673 861 1657 566 969 1891 1718 1801 200 1817 235 711 372 319 507 483 1332 968 1138 246 1082 1074 1569 1774 488 358 1713 350 583 381 418 300 1011 416 563 748 1858 837 1678 1336 1516 1177 1449 1664 1991 1465 1159 1653 1724 311 1360 902 1182 1768 1471 1606 1813 1925 825 122 1647 1790 1575 323 153 33 1825 1343 1183 1707 1724 1839 1190 1936 442 1370 206 1530 1142 561 952 478 25 1666 382 1092 418 720 1864 652 313 1878 1268 993 1446 1881 893 1416 319 577 1147 688 1155 726 1336 1354 1419 217 1236 213 1715 101 946 1450 135 297 1962 1405 455 924 26 569 755 64 1459 1636 395 1417 138 924 1360 893 1216 1231 1546 1104 252 697 1602 1794 1565 1945 1738 941 1813 1829 714 280 369 1861 1466 1195 1284 1936 78 1988 145 1541 1927 833 135 913 1214 405 23 1107 390 242 309 964 1311 724 284 342 1550 1394 759 1860 28 1369 1417 362 747 1732 26 1791 646 1817 1392 666 762 1297 945 507 58 928 1972 811 170 1660 1811 1969 573 242 1297 74 581 1513 1258 1311 547 627 942 1965 945 343 1633 197 843 249 77 320 611 1674 303 1346 148 533 1800 259 916 1498 1058 365 973 451 1143 1121 1033 126 595 726 1232 894 1584 878 1076 1796 257 531 144 740 1033 630 471 919 773 1276 1523 1195 475 667 40 91 1336 350 1650 970 1712 542 1927 168 1107 917 1271 649 1006 1428 20 1341 1283 774 1781 1427 1342 316 1317 1162 1333 991 1288 1853 1917 210 1589 1744 1942 962 557 1444 396 1330 378 625 1776 179 434 290 870 961 1365 226 605 1842 1629 1421 1883 108 102 1068 671 1086 692 1053 45 660 1746 1351 399 1308 833 42 1219 491 248 503 499 3 1965 1043 1452 604 1736 1974 675 14 1491 1757 1116 1520 1540 983 108 15 1030 742 1535 423 1802 1622 1401 1801 167 824 230 404 1722 814 1222 1626 1177 1772 1645 27 1061 1848 1031 1659 1725 1862 959 362 728 1644 957 934 1160 1862 915 995 1201 119 1191 259 963 1889 
Child1: 
3 5 14 15 16 20 23 25 26 26 27 28 33 34 40 42 45 58 61 64 74 76 77 78 91 101 102 108 108 119 122 126 135 135 138 138 139 144 145 148 153 167 168 170 179 188 197 200 203 206 210 213 217 220 221 226 230 235 242 242 246 248 249 252 257 259 259 280 284 290 297 300 303 309 311 313 316 319 319 320 323 331 333 342 343 350 350 357 358 362 362 365 369 371 372 378 381 382 390 395 396 399 401 404 404 404 405 416 418 418 423 434 442 451 455 471 475 478 483 488 489 491 499 503 507 507 531 532 533 538 542 547 557 559 561 563 566 567 569 573 577 581 583 595 604 604 605 605 611 625 627 630 646 649 652 654 660 666 667 671 675 688 690 692 697 697 711 711 713 714 714 720 724 726 726 727 728 730 740 741 742 746 747 748 755 756 759 762 762 773 774 804 807 811 814 824 825 826 833 833 837 840 842 843 844 855 861 865 870 878 878 893 893 894 902 913 915 916 917 919 924 924 928 934 941 942 945 945 946 952 957 959 961 962 963 964 967 968 969 970 973 983 991 993 995 1006 1011 1030 1031 1033 1033 1043 1044 1053 1058 1061 1065 1068 1074 1075 1076 1082 1086 1092 1104 1107 1107 1110 1116 1121 1132 1138 1142 1143 1147 1153 1155 1155 1156 1159 1160 1162 1173 1177 1177 1179 1182 1183 1185 1190 1191 1195 1195 1201 1214 1214 1215 1216 1219 1221 1222 1231 1232 1235 1236 1242 1253 1258 1268 1271 1274 1276 1283 1284 1288 1296 1297 1297 1305 1308 1311 1311 1317 1330 1332 1333 1336 1336 1336 1341 1342 1343 1346 1349 1351 1354 1356 1360 1360 1365 1369 1370 1372 1380 1381 1392 1394 1395 1396 1401 1405 1414 1416 1417 1417 1419 1421 1427 1428 1436 1444 1446 1449 1450 1452 1459 1465 1466 1468 1471 1484 1491 1498 1508 1509 1513 1516 1520 1523 1530 1535 1540 1541 1546 1547 1550 1565 1569 1575 1582 1584 1589 1595 1602 1606 1622 1626 1629 1633 1635 1636 1644 1645 1647 1647 1650 1651 1653 1655 1657 1659 1660 1664 1665 1666 1673 1674 1678 1707 1712 1713 1715 1717 1718 1721 1722 1724 1724 1725 1732 1736 1738 1742 1744 1745 1746 1757 1760 1768 1772 1773 1774 1776 1781 1783 1785 1790 1791 1794 1796 1800 1801 1801 1802 1811 1813 1813 1817 1817 1825 1829 1833 1839 1842 1842 1848 1853 1858 1860 1861 1862 1862 1864 1878 1881 1883 1889 1891 1892 1896 1917 1925 1927 1927 1927 1936 1936 1942 1945 1947 1962 1965 1965 1969 1972 1974 1984 1988 1991 1993 
2017-05-05  21:43:11
Time in microseconds for sorting CHILD 1: 62 microseconds
Child2: 
2017-05-05  21:43:11
3 5 14 15 16 20 23 25 26 26 27 28 33 34 40 42 45 58 61 64 74 76 77 78 91 101 102 108 108 119 122 126 135 135 138 138 139 144 145 148 153 167 168 170 179 188 197 200 203 206 210 213 217 220 221 226 230 235 242 242 246 248 249 252 257 259 259 280 284 290 297 300 303 309 311 313 316 319 319 320 323 331 333 342 343 350 350 357 358 362 362 365 369 371 372 378 381 382 390 395 396 399 401 404 404 404 405 416 418 418 423 434 442 451 455 471 475 478 483 488 489 491 499 503 507 507 531 532 533 538 542 547 557 559 561 563 566 567 569 573 577 581 583 595 604 604 605 605 611 625 627 630 646 649 652 654 660 666 667 671 675 688 690 692 697 697 711 711 713 714 714 720 724 726 726 727 728 730 740 741 742 746 747 748 755 756 759 762 762 773 774 804 807 811 814 824 825 826 833 833 837 840 842 843 844 855 861 865 870 878 878 893 893 894 902 913 915 916 917 919 924 924 928 934 941 942 945 945 946 952 957 959 961 962 963 964 967 968 969 970 973 983 991 993 995 1006 1011 1030 1031 1033 1033 1043 1044 1053 1058 1061 1065 1068 1074 1075 1076 1082 1086 1092 1104 1107 1107 1110 1116 1121 1132 1138 1142 1143 1147 1153 1155 1155 1156 1159 1160 1162 1173 1177 1177 1179 1182 1183 1185 1190 1191 1195 1195 1201 1214 1214 1215 1216 1219 1221 1222 1231 1232 1235 1236 1242 1253 1258 1268 1271 1274 1276 1283 1284 1288 1296 1297 1297 1305 1308 1311 1311 1317 1330 1332 1333 1336 1336 1336 1341 1342 1343 1346 1349 1351 1354 1356 1360 1360 1365 1369 1370 1372 1380 1381 1392 1394 1395 1396 1401 1405 1414 1416 1417 1417 1419 1421 1427 1428 1436 1444 1446 1449 1450 1452 1459 1465 1466 1468 1471 1484 1491 1498 1508 1509 1513 1516 1520 1523 1530 1535 1540 1541 1546 1547 1550 1565 1569 1575 1582 1584 1589 1595 1602 1606 1622 1626 1629 1633 1635 1636 1644 1645 1647 1647 1650 1651 1653 1655 1657 1659 1660 1664 1665 1666 1673 1674 1678 1707 1712 1713 1715 1717 1718 1721 1722 1724 1724 1725 1732 1736 1738 1742 1744 1745 1746 1757 1760 1768 1772 1773 1774 1776 1781 1783 1785 1790 1791 1794 1796 1800 1801 1801 1802 1811 1813 1813 1817 1817 1825 1829 1833 1839 1842 1842 1848 1853 1858 1860 1861 1862 1862 1864 1878 1881 1883 1889 1891 1892 1896 1917 1925 1927 1927 1927 1936 1936 1942 1945 1947 1962 1965 1965 1969 1972 1974 1984 1988 1991 1993 
Time in microseconds for sorting CHILD 2: 83377 microseconds
Parent:
3 5 14 15 16 20 23 25 26 26 27 28 33 34 40 42 45 58 61 64 74 76 77 78 91 101 102 108 108 119 122 126 135 135 138 138 139 144 145 148 153 167 168 170 179 188 197 200 203 206 210 213 217 220 221 226 230 235 242 242 246 248 249 252 257 259 259 280 284 290 297 300 303 309 311 313 316 319 319 320 323 331 333 342 343 350 350 357 358 362 362 365 369 371 372 378 381 382 390 395 396 399 401 404 404 404 405 416 418 418 423 434 442 451 455 471 475 478 483 488 489 491 499 503 507 507 531 532 533 538 542 547 557 559 561 563 566 567 569 573 577 581 583 595 604 604 605 605 611 625 627 630 646 649 652 654 660 666 667 671 675 688 690 692 697 697 711 711 713 714 714 720 724 726 726 727 728 730 740 741 742 746 747 748 755 756 759 762 762 773 774 804 807 811 814 824 825 826 833 833 837 840 842 843 844 855 861 865 870 878 878 893 893 894 902 913 915 916 917 919 924 924 928 934 941 942 945 945 946 952 957 959 961 962 963 964 967 968 969 970 973 983 991 993 995 1006 1011 1030 1031 1033 1033 1043 1044 1053 1058 1061 1065 1068 1074 1075 1076 1082 1086 1092 1104 1107 1107 1110 1116 1121 1132 1138 1142 1143 1147 1153 1155 1155 1156 1159 1160 1162 1173 1177 1177 1179 1182 1183 1185 1190 1191 1195 1195 1201 1214 1214 1215 1216 1219 1221 1222 1231 1232 1235 1236 1242 1253 1258 1268 1271 1274 1276 1283 1284 1288 1296 1297 1297 1305 1308 1311 1311 1317 1330 1332 1333 1336 1336 1336 1341 1342 1343 1346 1349 1351 1354 1356 1360 1360 1365 1369 1370 1372 1380 1381 1392 1394 1395 1396 1401 1405 1414 1416 1417 1417 1419 1421 1427 1428 1436 1444 1446 1449 1450 1452 1459 1465 1466 1468 1471 1484 1491 1498 1508 1509 1513 1516 1520 1523 1530 1535 1540 1541 1546 1547 1550 1565 1569 1575 1582 1584 1589 1595 1602 1606 1622 1626 1629 1633 1635 1636 1644 1645 1647 1647 1650 1651 1653 1655 1657 1659 1660 1664 1665 1666 1673 1674 1678 1707 1712 1713 1715 1717 1718 1721 1722 1724 1724 1725 1732 1736 1738 1742 1744 1745 1746 1757 1760 1768 1772 1773 1774 1776 1781 1783 1785 1790 1791 1794 1796 1800 1801 1801 1802 1811 1813 1813 1817 1817 1825 1829 1833 1839 1842 1842 1848 1853 1858 1860 1861 1862 1862 1864 1878 1881 1883 1889 1891 1892 1896 1917 1925 1927 1927 1927 1936 1936 1942 1945 1947 1962 1965 1965 1969 1972 1974 1984 1988 1991 1993 
2017-05-05  21:43:11
Time in microseconds for sorting Parent: 51 microseconds

不同的 运行s 显示 child 2 的处理时间发生了巨大变化。我观察到的值是:83,377; 73,929; 78,977; 83,977; 94,159; 81,526 微秒。

您可能会从由少量线程排序的大型数据集的线程中获得一些好处(比如 10,000 行数据,但只有 8 个线程,每个线程对 1250 行数据进行排序),但即使那样也可能不会。当您将线程数增加到超过系统内核数时,您从多线程中获得的好处会越来越少。

你有几个问题:

  1. 如评论和 Jonathan 的回答所述,您调用 exec 并在您的线程完成之前替换您的整个过程图像(并且可能在它们实际开始之前,因为它们可能还没有被赋予它们的第一个时间片)
  2. 如果你移动它,你仍然有问题,你的 printArray 函数是 运行 并行 到你的排序线程,而不是之后
  3. 如果您修复了该问题,您仍然会遇到 printArray 线程未正确启动的问题(输入指针可能无效),其原因与排序线程的原因相同,详情如下所述
  4. 如果你修复打印,你的排序线程调用是完全错误的(下面有很多细节)
  5. 如果您修复了线程调用,您的代码仍然没有按照您声称的那样执行:继续为输入数组的越来越小的子范围启动新的子线程

让我们从pthread_create的原型开始,线程函数的声明,线程创建调用:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);

这需要一个形状为 void* start_routine(void *) 的函数作为它的第三个参数。但是,你有

void mergeSort(int arr[], int l, int r) { ... }

尽管如此,将被调用,只有第一个参数具有定义的值。我很惊讶你的编译器没有警告这个。

现在,考虑以下调用中 pthread_create 的第四个参数:

    ans1 = pthread_create(&thread1, NULL,
                          mergeSort,
                          (arr3, (arr_size / 2) - 1 ,arr_size - 1 )) ;

它采用表达式 (arr3, (arr_size / 2) - 1 ,arr_size - 1 )。但是,C 没有元组类型,即使有,它们也不能转换为 void*。相反,它使用逗号运算符 , 丢弃 前两个表达式的结果,因此您实际上使用 arr_size - 1 的整数值作为指针参数。

我预计它会在尝试启动子线程时崩溃 - 您没有说明您的程序是如何失败的,但 SEGV 很常见。您可以在调试器中捕获它们,但它会位于 pthread 库代码中的某个位置,因此可能帮助不大。

针对您的问题的合理解决方案看起来像这样未经测试且从未编译的示例代码:

/* use this for the fourth argument to pthread_create */
struct Range {
  int *array;
  int left;
  int right;
  pthread_t thread;
};

void mergeSortRange(Range *r) {
  const int width = (right - left);
  const int mid = left + (width/2);
  if (width > THRESHOLD) {
    /* wide enough to be worth a child thread */
    Range left = { r->array, r->left, mid };
    Range right = { r->array, mid+1, r->right };
    pthread_create(&left.thread, NULL,
                   mergeSortRangeThreadFunction,
                   &left);
    mergeSortRange(&right);
    pthread_join(left.thread);
    mergeSortedHalved(r->array, r->left, mid, r->right);
  } else {
    regularSingleThreadedMergeSort(r->array, r->left, r->right);
  }
}

/* this is what you pass to pthread_create */
void* mergeSortRangeThreadFunction(void *data) {
  Range *r = (Range *)data;
  mergeSortRange(r);
  return data;
}

不过,即使 THRESHOLD 设置得很好,使用线程池也比反复启动和停止线程要好。

最后,当然,您不需要使用递归来启动这些线程并填充这些 Range 结构 - 您可以只创建一个 size/THRESHOLD + 1 范围描述符的数组,创建一个线程每个核心,然后找出一些逻辑来决定何时允许合并两个连续的范围。