【问题标题】:Merge Sort (pthreads) C++ [closed]合并排序(pthreads)C++ [关闭]
【发布时间】:2014-10-08 03:21:20
【问题描述】:

我对 pthreads 有点陌生,我正在尝试创建一个对 1​​00 万个随机生成的整数进行排序的程序。我似乎对线程失去了一些控制。第一次运行时,代码只产生一个线程,但是当随后运行时,线程,线程乘以失控。由于我真的不知道问题出在哪里,所以我提供了下面的代码。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>

#define N           8          /* # of thread */
#define NUM_INTS    10000      //ideally should be able to sort 1,000,000

int int_list[NUM_INTS];

/* structure for array index
 * used to keep low/high end of sub arrays
 */
typedef struct Arr {
    int low;
    int high;
} ArrayIndex;

void merge(int low, int high) {
    int mid = (low+high)/2;
    int left = low;
    int right = mid+1;

    int list_b[high-low+1];
    volatile int i, cur = 0;

    while((left <= mid) && (right <= high)) {
        if (int_list[left] > int_list[right])
            list_b[cur++] = int_list[right++];
        else
            list_b[cur++] = int_list[right++];
    }

    while(left <= mid)
        list_b[cur++] = int_list[left++];

    while(right <= high)
        list_b[cur++] = int_list[left++];

    for (i = 0; i < (high-low+1) ; i++)
        int_list[low+i] = list_b[i];
}

void * mergesort(void *a){
    ArrayIndex *pa = (ArrayIndex *)int_list;
    int mid = (pa->low + pa->high)/2;

    ArrayIndex aIndex[N];
    pthread_t thread[N];

    aIndex[0].low = pa->low;
    aIndex[0].high = mid;

    aIndex[1].low = mid+1;
    aIndex[1].high = pa->high;

    if (pa->low >= pa->high)
        return 0;

    volatile int i;
    for(i = 0; i < N; i++)
        pthread_create(&thread[i], NULL, mergesort, &aIndex[i]);

    for(i = 0; i < N; i++)
        pthread_join(thread[i], NULL);

    merge(pa->low, pa->high);

    pthread_exit(NULL);
}

int main(){
    volatile int i;
    struct timeval start_time, end_time;

    srand(getpid());

    for(i=0; i<NUM_INTS; i++)
        int_list[i] = rand();

    ArrayIndex ai;
    ai.low = 0;
    ai.high = NUM_INTS/sizeof(int_list[0])-1;
    pthread_t thread;

    pthread_create(&thread, NULL, mergesort, &ai);
    pthread_join(thread, NULL);

    return 0;
}

gdb 输出:

(gdb) run
Starting program: /.../sort.o 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff6fd5700 (LWP 25801)]
[Thread 0x7ffff6fd5700 (LWP 25801) exited]

Computation Time: 38006 micro-seconds.
[Inferior 1 (process 25797) exited normally]
(gdb) run
Starting program: /.../sort.o 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff6fd5700 (LWP 25804)]
[New Thread 0x7ffff67d4700 (LWP 25805)]
[New Thread 0x7ffff5fd3700 (LWP 25806)]
[New Thread 0x7ffff57d2700 (LWP 25807)]
[New Thread 0x7ffff4fd1700 (LWP 25808)]
[New Thread 0x7fffef7fe700 (LWP 25811)]
[New Thread 0x7fffeeffd700 (LWP 25810)]
...
[New Thread 0x7ffeca6ec700 (LWP 26148)]

Program received signal SIGINT, Interrupt.
[Switching to Thread 0x7ffee8728700 (LWP 26088)]
__GI___nptl_create_event () at events.c:25
25  events.c: No such file or directory.

【问题讨论】:

  • 重新思考这个:ai.high = NUM_INTS/sizeof(int_list[0])-1;,在合并排序中,这个:ArrayIndex *pa = (ArrayIndex *)int_list;
  • 对于任何寻求良好并行排序实现的人,我建议您查看:parallelQuicksort.c

标签: c++ pthreads mergesort


【解决方案1】:

问题是您尝试通过为每个子问题启动一个新线程来实现递归分治并行,直到线程被赋予单个数组项以“排序”。由于多种原因,这种方法是完全错误的。仅举一个例子,对包含 100 万个项目的数组进行排序将需要在递归的叶调用中使用 100 万个线程,并且在上述所有递归级别中需要另外 100 万个线程。即使你引入了一些粒度——一个阈值之后递归变为串行——线程的总数仍然可能非常大,除非你的阈值类似于NUM_INTS/N

即使不计算上述内容,您的实现也存在一些错误:

  • 在每个递归级别,您启动 N 个线程,即使工作被分成两半。 aIndex[i] 对于 i>1 未初始化,因此相应线程在其输入参数中接收垃圾。
  • 您将int_list(指向int 的指针)转换为指向ArrayIndex 的指针。

有几种方法可以修复设计:

  • 简单的方法是引入一个适当的阈值,之后递归变为串行,正如我上面所说的。
  • 更复杂的一种——但也更通用和灵活——是实现一个线程池和一个由线程处理的任务池/队列;因此,当您将给定数组分成两半时,您会创建两个任务来处理每一半,并将这些任务提交到线程从中获取工作的工作队列。请注意,为了获得良好的性能,您仍然需要设置一些粒度大小以便每个任务有足够的工作量,但这将比限制线程数所需的阈值小得多。
  • 正确的做法,尤其是对于生产代码,采用具有适当原语的库或并行技术用于递归并行,例如 Intel's Threading Building Blocks () 或 Microsoft 的并行模式库 ()。

另见一些链接(通常,谷歌“并行合并排序 C++”)

【讨论】:

  • 我有点意识到我对这个问题采取了完全错误的方法(并且在此过程中犯了相当多的愚蠢错误)在发布后(一个盯着代码的糟糕案例)长)。我发现快速排序更容易适应颚化。不过,谢谢。
猜你喜欢
  • 2019-03-17
  • 2017-10-13
  • 1970-01-01
  • 1970-01-01
  • 2016-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多