【问题标题】:Implementation of merge sort using threads and fork使用线程和fork实现归并排序
【发布时间】:2017-10-04 02:56:29
【问题描述】:

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

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

这是第二个孩子的代码:

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;
}

【问题讨论】:

  • 是的,线程和进程传统上是不分性别的。无论如何,为什么在线程完成之前用date 替换整个子进程? execl 调用应该替换整个过程为date,然后退出。
  • @EugeneSh。已编辑:)
  • @Useless 即使我将日期代码放在第三个 'pthread_join' 之后,它仍然不起作用。
  • 您还(尝试)与 mergeSort 线程并行运行打印数组 - 在它们都完成之前它不应该运行(在这种情况下,您可以只 join 他们和然后同步运行printArray
  • 关于性能:不要期望线程解决方案更快...首先,创建新线程需要相当多的开销。要涵盖这一点,您需要大量数据才能看到任何好处。但是使用您的算法,您也需要大量线程,因此需要大量开销,此外,这些线程中的大多数无论如何都将处于非活动状态,因为不能同时活动的线程多于您拥有的 CPU 内核你的系统...

标签: c unix pthreads fork mergesort


【解决方案1】:

程序因调用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()或更高分辨率的计时机制,然后localtime()gmtime()创建一个细分时间,然后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");

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

亚秒级解析时间

我需要以毫秒为单位确定时间。

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

#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(),可能还有其他问题需要解决——可能还有其他问题需要解决。但解决这个问题是让您的线程运行完成的关键步骤。

创建工作代码

从问题中获取修改后的代码,对其应用基本的“清洁”(确保它在严格的警告选项下干净地编译),该程序似乎可以工作。传递一个指针和两个 int 值的“int 数组”方法在 64 位系统上不起作用,因此我创建了一个 struct Sort 来包含信息。我还将“开始时钟”和“停止时钟”调用移至gettimeofday(),使其更靠近被测量的代码(调用代码中没有打印)。我添加了 macOS Sierra 10.12.4 (GCC 7.1.0) 所需的标头。该代码还在对任何输入数据进行排序之前打印输入数据。清理工作基本上是“围绕”排序代码。核心排序算法根本没有改变。

#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

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

当我尝试将数组大小从 10 增加到 10,000 时,线程子进程没有完成。这意味着线程创建在某处失败。错误报告有缺陷(我很懒)。切换到 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

不同的运行表明孩子 2 的处理时间存在巨大差异。我观察到的值是:83,377; 73,929; 78,977; 83,977; 94,159; 81,526 微秒。

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

【讨论】:

  • 谢谢乔纳森!尽管如此,它仍然无济于事。我需要以毫秒为单位确定时间。
  • 哦?运行良好的 date 将无济于事 - 它最多会在几秒钟内报告。
  • 是的。我正在使用 struct timeval 和函数 gettimeofday 来实现它。效果很好。现在最后一件事是用线程实现 Child 2..
  • 我已经编辑了代码,但仍然无法正常工作,我相信还有一些工作要做。
  • 我尝试编译修改后的代码。它离通过我的基本清洁度测试还差得很远。我使用gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition ms83.c -o ms83编译文件ms83.c,遇到了很多问题。一个错误是您创建了两个线程但两次都传递了&amp;thread1,然后尝试加入thread2——它没有被初始化。基本上,在我看来,在代码足够干净可以使用这些标志进行编译之前,真的不值得尝试检查代码是否存在错误。我允许一些松懈,但不多。
【解决方案2】:

你有几个问题:

  1. 如 cmets 和 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 范围描述符数组,每个内核创建一个线程,然后图找出一些逻辑来决定何时允许合并两个连续的范围。

【讨论】:

  • 谢谢没用!我还在努力,完成后我会更新。
  • 我已经编辑了代码,它仍然无法正常工作,我相信还有一些工作要做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-11
  • 2019-07-29
  • 2016-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多