【发布时间】:2014-07-23 20:21:53
【问题描述】:
我有以下代码设置:
#define TSIZE 32
#define TNUM 24000000
#define CORES 4
/* Byte-wise swap two items of size SIZE. */
#define SWAP(a, b, size) \
do \
{ \
size_t __size = (size); \
char *__a = (a), *__b = (b); \
do \
{ \
char __tmp = *__a; \
*__a++ = *__b; \
*__b++ = __tmp; \
} while (--__size > 0); \
} while (0)
char* TWEETS;
size_t partition(void* arr, size_t left, size_t right, int (*compar)(const void* , const void*))
{
char* cArr = (char*) arr;
size_t i;
size_t pivotIndex = (left+right)/2;
char* pivotValue = &cArr[(size_t)TSIZE * right];
size_t index = left;
SWAP(&cArr[(size_t)TSIZE * pivotIndex], &cArr[(size_t)TSIZE * right], (size_t)TSIZE);
for(i = left; i < right; i++) {
if(compar((void*) &cArr[(size_t)TSIZE * i], (void*) pivotValue) < 0) {
SWAP(&cArr[(size_t)TSIZE * i], &cArr[(size_t)TSIZE * index], (size_t)TSIZE);
index++;
}
}
SWAP(&cArr[(size_t)TSIZE * index], &cArr[(size_t)TSIZE * right], (size_t)TSIZE);
return index;
}
void quicksort(void* base, size_t left, size_t right, int (*compar)(const void* , const void*))
{
if(left < right) {
size_t pivot = partition(base, left, right, compar);
#pragma omp task
quicksort(base, left, pivot-1, compar);
#pragma omp task
quicksort(base, pivot+1, right, compar);
}
}
int main(int argc, char** argv) {
omp_set_dynamic(0);
omp_set_num_threads(CORES);
TWEETS = (char*) malloc((size_t)TNUM * (size_t)TSIZE * (size_t)CORES * (size_t)sizeof(char));
if(TWEETS == NULL) exit(1);
readData();
#pragma omp parallel
{
#pragma omp single
quicksort(TWEETS, 0, ((size_t)CORES*(size_t)TNUM)-(size_t)1, compare);
}
free(TWEETS);
}
所以首先,请原谅大量的 (size_t) 演员,我是在绝望中这样做的。
我在这里做什么
我正在读取一个包含 2400 万行文本的文本文件,每行包含 32 个字节的字符。然后根据比较函数对行进行排序,我在这里省略了。我可以保证这个功能可以正常工作,而不是我的麻烦。它始终返回 -1、0 或 1。
我也在尝试并行化快速排序算法。代码行随着我使用的内核数量而增长,例如1 核 = 2400 万,2 核 = 4800 万,依此类推。
什么已经在起作用
只要文件大小保持在 4800 万行文本以下,工作已经在使用 1 到 8 个内核对文件进行排序。
我的问题是什么
我的问题是,一旦我尝试对包含 7200 万行或更多文本的文件进行排序,快速排序算法就会遇到分段错误。我已经尽我所能用gdb调试了代码,出错的代码是这一行:
SWAP(&cArr[(size_t)TSIZE * i], &cArr[(size_t)TSIZE * index], (size_t)TSIZE);
是for循环中partition函数中的swap调用。我还可以看到,此时变量“right”的值为 18446744073709551615 (2^64-1),这是导致分段错误的原因。 “正确”的最大值应该是 TSIZE * TNUM * CORES。由于这个数字很大,我唯一的猜测是算法中的某个地方发生了溢出。
好吧,这里有个问题:算法和整个程序在保持
那么,为什么它可以处理多达 48.000.000 行的文本,以及为什么在拥有更多文本时会出现段错误?我的错在哪里?
【问题讨论】:
-
会不会是因为你在除以2之前左右相加,溢出了?
-
对此,请尝试
left + (right - left)/2(即使不是您的问题,您也应该这样做)。 -
@WhozCraig 那是正确的表达方式,正试图为它找到一个确定的来源。
-
(left+right)/2 不太可能是问题的原因,因为段错误发生在未使用 pivotIndex 的 for 循环中的交换处。感谢 WhozCraig 的建议。
-
我认为@LasseV.Karlsen 有答案,但您还应该考虑交换字符串列表 pointers 而不是实际的字符串本身。这将使您的代码运行得更快 — 只需 3 个处理器操作码即可交换指针,而您的
SWAP宏将需要数十个。
标签: c algorithm sorting segmentation-fault quicksort