【发布时间】:2020-03-25 01:19:03
【问题描述】:
我是一名学生,我需要使用线程来实现 MergeSort。当我测试程序时,与递归排序相比,使用线程进行排序需要相同或更多的时间。
我们得到了带有基本 MergeSort 的预制文件,我不能更改 merge() 或 mergesort() 函数,但我需要实现 submergeSortThreads()。 我正在计算带有信号量的线程(用户决定在排序期间将创建多少个线程),没有信号量数组不会正确排序,因为我认为竞争条件...
我正在运行程序并使用以下命令从文件中读取数字:
$ time cat rand_stevila.bin | ./mergeSort 10000
线程运行(n == 允许的最大线程数):
$ time cat rand_stevila.bin | ./mergeSort 10000 -t -n 5
以下是代码的一些部分,它们对问题很重要:
sem_t *sem_c;
int *polje;
unsigned int max_paralelizacij = 1000;
struct{
int *array;
int min;
int max;
void(*function)(int *, int, int, int, int);
}typedef thread_args;
void* thread_fun(void* args){
thread_args *thr_arg = (thread_args*)args;
mergeSort((*thr_arg).array,(*thr_arg).min,(*thr_arg).max,(*thr_arg).function);
return 0;
}
// simple recursive sort
void submergeSortSimple(int* array, int min1, int max1, int min2, int max2){
mergeSort(array, min1, max1, submergeSortSimple);
mergeSort(array, min2, max2, submergeSortSimple);
}
//function that swaps submergeSortSimple(), while sorting with threads
void submergeSortThread(int* array, int min1, int max1, int min2, int max2){
if(sem_trywait(sem_c)==-1){ //if there is already max_threads, program continues with simple sorting
mergeSort(array, min1, max1, submergeSortSimple);
mergeSort(array, min2, max2, submergeSortSimple);
return;
}
thread_args arg1;
arg1.array = array;
arg1.min = min1;
arg1.max = max1;
arg1.function = submergeSortThread;
pthread_t tid1;
pthread_create(&tid1, 0, &thread_fun, &arg1);
if(sem_trywait(sem_c)==-1){
pthread_join(tid1,NULL);
mergeSort(array, min2, max2, submergeSortSimple);
return;
}
pthread_t tid2;
thread_args arg2;
arg2.array = array;
arg2.min = min2;
arg2.max = max2;
arg2.function = submergeSortThread;
pthread_create(&tid2, 0, &thread_fun, &arg2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return;
}
// must not be changed
void mergeSort(int *array, int min, int max, void(*submergeSort)(int *, int, int, int, int) ){
int mid;
if(min < max){
mid=(min+max)/2;
submergeSort(array, min, mid, mid+1, max);
merge(array, min, mid, max);
}
}
// must not be changed
void merge(int *arr, int min,int mid,int max)
{
// drugi korak algoritma mergeSort
int *tmp = malloc((max-min+1)*sizeof(int));
int i,j,k,m;
j=min;
m=mid+1;
for(i=min; j<=mid && m<=max ; i++)
{
if(arr[j]<=arr[m])
{
tmp[i-min]=arr[j];
j++;
}
else
{
tmp[i-min]=arr[m];
m++;
}
}
if(j>mid)
{
for(k=m; k<=max; k++)
{
tmp[i-min]=arr[k];
i++;
}
}
else
{
for(k=j; k<=mid; k++)
{
tmp[i-min]=arr[k];
i++;
}
}
for(k=min; k<=max; k++){
arr[k]=tmp[k-min];
}
free(tmp);
}
int main(int argc, char *argv[])
{
#define NO_PAR 0
#define THREAD_PAR 2
int technique= NO_PAR;
void (*submergeSortFun)(int *, int, int, int, int);
submergeSortFun = submergeSortSimple;
while(1){
int c;
c = getopt(argc, argv, "ptn:");
if(c==-1){
break;
}
switch(c){
case 't':
technique = THREAD_PAR;
submergeSortFun = submergeSortThread;
break;
case 'n':
max_paralelizacij = atoi(optarg);
break;
default:
printHelp(argc, argv);
return 0;
}
}
if(technique == THREAD_PAR){
sem_unlink("/C\0");
sem_c = sem_open("/C", O_RDWR|O_CREAT|O_EXCL, 0660, max_paralelizacij);
if(sem_c == SEM_FAILED){
perror("Napaka pri ustvarjanju semaforja!\n");
}
}
int i;
int size;
int *arr;
if(optind >= argc){
printHelp(argc, argv);
return -1;
}
size = atoi(argv[optind]);
// TODO: inicializacija za razlicne tehnike
switch(technique){
case NO_PAR:
arr = malloc(sizeof(int)*size);
break;
case THREAD_PAR:
arr = malloc(sizeof(int)*size);
break;
}
char buffer[101];
// reading numbers from file
for(i=0; i < size; i+=1){
read(0, &arr[i], 4);
}
//measure time and sorting
clock_t start = clock();
mergeSort(arr, 0, size-1, submergeSortFun);
clock_t end = clock();
float seconds = (float)(end - start) / CLOCKS_PER_SEC;
for(i=0; i<size; i++){
printf("%d ",arr[i]);
}
printf("\n");
// TODO: ciscenje za razlicnimi tehnikami
switch(technique){
case NO_PAR:
free(arr);
sem_close(sem_c);
break;
case THREAD_PAR:
free(arr);
sem_close(sem_c);
break;
}
printf("\n\n CAS : %f\n\n",seconds);
return 0;
}
【问题讨论】:
-
我们在谈论要排序的数据量是多少?使用线程会带来相当多的开销,线程必须使用其所有设施创建并在运行后销毁。如果有足够的数据,您将只能从多个线程中获利,这样加速可以补偿线程管理成本......
-
好吧,
10000对于数组大小来说有点小,所以所有线程创建的开销可能超过实际排序,尝试使用更大的数组,例如10000000 -
我正在排序 100 1k 10k 100k 和 1M 数字,使用线程排序总是更慢,除了 1M 数字我得到 1-5ms 更快的排序。另一方面,使用 fork() 排序(进程)我可以更快地排序......我还在使用 4GB RAM 和 2 CPE 在 virtualbox 上运行程序,如果这会影响排序速度?
-
题外话:atoi 通常是将字符串转换为整数的错误选择,因为您无法区分无效输入和合法提供的零值。在给定的情况下,我们可能会假设零是无效输入——但你至少应该检查(对于负值,也一样,因为你不使用 unsigned int...)。
-
好吧,有了 1M,您终于通过了创建线程的成本被摊销的地步……在 POSIX 系统上,线程和进程实际上差别很小。与线程相比,使用 fork 进行排序不会给您带来任何加速除非您做了一些根本错误的事情。除此之外,这些不同的进程各自使用自己的内存(要排序的数据被复制),所以你很难重新组合结果......
标签: c multithreading algorithm mergesort