【问题标题】:Merging 2 quick sorted arrays results in all 0s合并 2 个快速排序的数组会导致全 0
【发布时间】:2019-05-03 03:16:38
【问题描述】:

我正在使用多线程程序对数组进行排序。首先,我将数组分成两半。 1个线程对前半部分进行排序,另一个线程对后半部分进行排序,最后一个线程将这两部分合并在一起。我使用快速排序对每一半进行排序。问题是,当我打印排序后的数组时,它只是 0。

我一直在使用打印语句来检查数组的内容。最初,快速排序似乎有效,但现在我得到了正确的数组,但添加了额外的数字。我认为这个问题可能是内存被覆盖,但我真的不确定,所以我包含的代码可能比必要的多。

*注意:mainarr 是一个全局变量,声明为:int *mainarr

//function to merge two halves in result array
void merge(int l[], int r[], int size_left, int size_right)
{
    //iterator variables, start at 0
    int i = 0, j = 0, k = 0;

    // Traverse both array
    while (i < size_left && j < size_right)
    {
        if (l[i] < r[j]){
            mainarr[k] = l[i];
            i++;
            k++;
        }
        else{
            mainarr[k] = r[j];
            k++;
            j++;
        }
    }

    // Store remaining elements of first array
    while (i < size_left){
        mainarr[k] = l[i];
        k++;
        i++;
    }

    // Store remaining elements of second array
    while (j < size_right){
        mainarr[k] = r[j];
        k++;
        j++;
    }
}

//compare function for qsort
int compare(const void *a, const void *b){
    return (*(int*)a - *(int*)b);
}

//thread begins control in this function
//this function is called from pthread_create
void *runner(void* param) {
    int threadID = atoi(param);
    int midpoint = size/2, index, r;
    int *left = malloc(midpoint*sizeof(int));
    int *right = malloc((size-midpoint)*sizeof(int));

    //if first thread, sort "left" array
    if(threadID == 1){
        int i;
        index=0;
        //create "left" array
        for(i=0; i < midpoint; i++){
            left[index] = mainarr[i];
            index++;
        }
        //sort array
        qsort(left, midpoint, sizeof(int), compare);
        printf("LEFT array: ");
        for(r = 0; r < size; r++)
            printf("%d ", left[r]);
    }
    //if second thread, sort "right" array
    else if(threadID == 2){
        int j;
        index=0;
        //create "right" array
        for(j=midpoint; j < size; j++){
            right[index] = mainarr[j];
            index++;
        }
        //sort array
        qsort(right, (size-midpoint), sizeof(int), compare);
        printf("RIGHT array: ");
        for(r = 0; r < size; r++)
            printf("%d ", right[r]);
    }
    //if third thread, merge the left and right arrays
    else if(threadID == 3){
        merge(left, right, 4, 5);
    }

    //empty else to satisfy convention
    else{}

    pthread_exit(0);
}

我一直使用的示例是数组[7,0,2,33,234,1,3,67,54]。所以,我希望排序后的“左”数组是[0,2,7,33],排序后的“右”数组是[1,3,54,67,234],整个排序后的数组是[0,1,2,3,7,33,54,67,234]。但是,实际排序的“左”数组是[0, 2, 7, 33, 0, 0, 37, 0, 0],实际排序的“右”数组是[1, 3, 54, 67, 234, 0, 132881, 0, 0],实际整个排序后的数组是[0, 0, 0, 0, 0, 0, 0, 0, 0]

我不确定问题出在哪里 - 无论是线程、内存覆盖本身还是其他问题。有什么帮助,谢谢。

更新/解决方案:我在 if 语句之外分配左右,所以当一个新线程启动时,它会清除左右数组的内容,导致结果全为 0。

【问题讨论】:

  • 听起来不自私,你真的可以找到this interesting。它适用于 C++,但在 C 中的想法是相同的。
  • 无论如何,您的合并例程至少看起来是正确的(看似)。 明显的是mainarr 的用法,我怀疑这是您的问题所在。如果它在这整个生命周期内都没有改变,那么你就完蛋了;顶部和底部分区都将尝试从偏移量 0 开始写入mainarr。此外,第三个线程是无用的,实际上使事情变得更糟。在排序之前,您不能合并左侧和右侧,这意味着您必须等待两个子分区完成才能合并到共同的父分区。综上所述,minimal reproducible example.

标签: c multithreading merge quicksort


【解决方案1】:

但是,实际排序的“左”数组是 [0, 2, 7, 33, 0, 0, 37, 0, 0],

不,不是。

实际排序的“正确”数组是 [1, 3, 54, 67, 234, 0, 132881, 0, 0]

不,不是。

您正在打印超出这些数组分配范围的元素。产生的行为是未定义的。您(不)幸运的是该程序不只是崩溃。请注意,这些数组实际范围内的值与您预期的一样。

实际的整个排序数组是 [0, 0, 0, 0, 0, 0, 0, 0, 0]

有点。

我可以相信这就是打印的内容,因为您正在合并由第三个线程分配的两个数组,并且它们的内容从未设置过。这里的行为又是未定义的,完全没有理由期望第三个线程会在每个线程分配自己的、单独的子数组对(并泄漏它们)时看到其他两个线程的排序结果。

我实际上并没有看到单独的合并线程的意义。在两个快速排序线程完成之前无法执行合并,并且由于它不能与其他线程同时运行,我认为没有理由不将这项工作留给主线程。总的来说,我建议这样做:

  • 每个都有一个(新)线程,用于快速排序两个半数组。或者,一个新线程用于一半,主线程处理另一半。
  • 执行标准的就地快速排序,而不是让线程执行任何内存分配或复制到临时空间。
  • 主线程加入其他线程后,它自己执行合并。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 2021-06-06
    • 2010-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多