我正在使用pthreads编写C程序。
目的是通过将给定数字的倍数作为参数传递来计算它们。
要相乘的数字和倍数的数量可以自由选择。
该程序用gcc -lpthread -Wall -Wextra in.c
编译,可执行文件用./a.out num amount num amount ...
调用
该程序为每个“输入对”分配内存,并为每次计算创建一个线程,
然后将所有线程连接起来,并将写入线程的内存区域打印到屏幕上。
问题是程序经常使至少一个输出留空(0x00
)。
通过重复相同的输入,很少会出现正确的结果。
例如,输入./a.out 10 3 7 5 3 4
的输出(此处已压缩)如下所示:
Thread 0 result: 10 20 30 or Thread 0 result: 0 0 0 but rarely the Thread 0 result: 10 10 0
Thread 1 result: 0 0 0 0 0 or Thread 1 result: 0 0 0 0 0 expected Thread 1 result: 7 14 21 28 35
Thread 2 result: 3 6 9 12 or Thread 2 result: 3 6 9 12 result: Thread 2 result: 3 6 9 12
因此,我找到了两种解决方法,但是它们都不能解决问题。它们包含在代码中,但已被注释掉。#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#define MAX_THREADS 100
int *thr_out[MAX_THREADS]; // global output record
// function to thread
void *threaded_mul(void* arguments[3])
{
int* out = arguments[0];
long num = (long)arguments[1];
long len = (long)arguments[2];
for(int i=0; i<len; i++)
out[i]=num*(i+1);
pthread_exit(NULL);
}
int main(int argc, char* argv[])
{
int amt_thr = argc/2; // one thread needs two arguments
int thr_i_num[amt_thr]; // number to generate multiples
int thr_o_len[amt_thr]; // how many multiples to generate
pthread_t thr_id[amt_thr]; // holds thread ids
long int thr_args[3]; // forms argument for pthread_create call
printf("%d threads needed\n",amt_thr);
for(int i=0; i<amt_thr;i++)
{ // calculate how much memory is needed for each thread
int oi = 2*i+1; // 0 1 2 3 -> 1 3 5 7
thr_o_len[i] = strtol(argv[oi+1], NULL, 10);
thr_i_num[i] = strtol(argv[oi], NULL, 10);
// allocate the memory
thr_out[i]=calloc(thr_o_len[i], sizeof(int));
}
for(int i=0; i<amt_thr; i++)
{ // create threads
thr_args[0] = (long)thr_out[i]; // address to write output to
thr_args[1] = thr_i_num[i]; // input 'val' for thread (number to multiply)
thr_args[2] = thr_o_len[i]; // output length 'len' for thread
pthread_create(&thr_id[i], NULL, (void*)threaded_mul, &thr_args);
//for(int i=0; i<32768; i++){} // either delay here
//pthread_join(thr_id[i],NULL); // or wait until the thread finishes
}
printf("joining threads\n");
for(int i=0; i<amt_thr; i++)
pthread_join(thr_id[i],NULL);
for(int t=0; t<amt_thr; t++)
{ // printing resuls
printf("Thread %d result: ",t);
for(int j=0; j<thr_o_len[t]; j++)
printf("%d ",thr_out[t][j]);
putchar('\n');
}
for(int i=0; i<amt_thr; i++)
free(thr_out[i]);
return 0;
}
我假设在创建线程之后,main
继续正常运行,并且该线程立即(在另一个内核上)启动,但是地址空间相同。我的观察是,在大多数情况下,至少有一个线程无法获取正确的参数,并且两个或多个线程执行相同的计算并写入相同的目的地,
因此,其他输出目的地保持不变。
如何避免这种行为?
编辑:根据您的回答,据我了解,问题是在新创建的线程从内存中读取其参数
&thr_args
之前,for
循环//create threads
已经在thr_args[]
中写入了新参数。但是参数必须是pthread_create
要求的指向内存的指针。Edit2:我通过将所有线程的所有输入(每个线程3个)写入内存而不是由于上面段落中所述的原因而在
thr_args[]
-loop中更新全局输入变量for
来解决了这个问题。
最佳答案
您可能应该发布预期的输出,但是从轻描淡写您的故事看来,您似乎不应在输出中找到零。
启动线程时,您传入了数组引用(thr_args [])。这意味着每个线程都会看到相同的参数,这是一个内存位置。您在线程创建循环中覆盖了此数组,因此任何特定线程所看到的都是与时间/os/#cores相关的。不太随机,但是该死的接近。
作为一个快速的技巧,我将围绕pthread_create的程序更改为:
void *x = memdup(thr_args, sizeof thr_args);
pthread_create(&thr_id[i], NULL, threaded_mul, x);
并在上面添加了一些功能:static void *memdup(void *p, size_t n) {
void *x;
if ((x = malloc(n))) {
memcpy(x, p, n);
return x;
} else {
abort();
}
}
和您的程序打印:Thread 0 result: 10 20 30
Thread 1 result: 7 14 21 28 35
Thread 2 result: 3 6 9 12
当然,这会泄漏。因此,您需要更正程序以将参数数组与线程相关联,并在该线程的连接成功后将其删除。
关于c - pthreads并行化错误结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66512055/