我在C中有一个数学函数,可以计算很多复杂的数学运算。该函数有一个标题:
double doTheMath(struct example *e, const unsigned int a,
const unsigned int b, const unsigned int c)
{
/* ... lots of math */
}
我想同时调用此函数100次。我读到pthreads
并认为它可能是我想要实现的目标的一个很好的解决方案。我的想法如下:
pthread_t tid[100];
pthread_mutex_t lock;
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n mutex init failed\n");
return 1;
}
for(i=0; i<100; i++) {
pthread_create(&(tid[i]), NULL, &doTheMath, NULL);
pthread_mutex_lock(&lock);
d += doTheMath(args);
pthread_mutex_unlock(&lock);
}
pthread_mutex_destroy(&lock);
我的问题:
doTheMath
? 修改
所以,总结一下:
我的功能使用数学加密/解密一些数据 - 所以我猜订单很重要
当我这样做的时候:
pthread_t tid[100];
for(i=0; i<100; i++)
pthread_create(&(tid[i]), NULL, &doTheMath, NULL);
它将创建我的100个线程(我的机器能够运行,当然)我不需要互斥锁,所以它会同时调用我的函数100次?
cPU核心怎么样?当我这样做的时候,我的所有CPU内核都会被完全加载吗?
只有一个单一函数调用只会加载我的CPU的一个核心,创建并运行100个(或更多)线程并调用我的函数将加载我所有的CPU核心 - 我在这里吗?
答案 0 :(得分:2)
如何将所需的所有参数传递给doTheMath?
您必须创建一个具有pthread_create
可接受签名的代理函数,该函数调用其正文中的实际函数:
struct doTheMathArgs {
struct example *e;
const unsigned int a, b, c;
};
callDoTheMath(void *data) {
struct doTheMathArgs *args = data;
doTheMath(args->e, args->a, args->b, args->c);
}
...
struct doTheMathArgs dtma;
dtma.e = ...;
...
dtma.c = ...;
pthread_create(&(tid[i]), NULL, &callDoTheMath, (void *) &dtma);
在这里使用线程是否真的有意义,这是否会像我想要的那样工作?我无法理解它,当我用互斥锁锁定函数调用时,它不会让我的函数同时调用100次,对吗?那我怎么能这样做呢?
除非您正在使用一台真正能够一次运行100个线程的计算机,否则您的代码将会降低整个过程的速度。你应该使用一些你的机器能够运行的线程。
要回答问题的其他部分,您必须告诉我们您的doTheMath
功能如何运作。每次调用此函数是否完全独立于其他函数?调用的顺序是否重要?
答案 1 :(得分:2)
是的,你可以用线程做到这一点。无论是实际调用它100次实际上是一个单独的问题,因为一旦你的所有CPU内核完全加载,尝试一次运行更多的东西可能会降低速度而不是随着处理器缓存效率的降低而增加速度。对于CPU密集型任务,最佳线程数可能是CPU核心数(或更多)。
关于您的具体问题:
Q1:当你使用phtread_create
时,最后一个参数是void *arg
,这是一个传递给你的线程的不透明指针。您通常会将其用作指向包含您要传递的参数的struct
的指针。这也可以用于返回计算的总和。请注意,您必须将do_the_maths
包装在合适的第二个函数中,以使其签名(返回值和参数)看起来像pthread_create
所期望的那样。
Q2。请参阅上面的一般警告太多线程,但使用这是一种有用的技术。
具体做法是:
您不希望以您的方式使用互斥锁。只需要一个互斥锁来保护访问公共数据(关键部分)的代码部分。
你们都创建了一个线程来调用doTheMath
,然后直接从主线程调用doTheMath
。这是不正确的。您应该只创建所有线程(在一个循环中),然后运行另一个循环以等待每个线程完成,并对返回的答案求和。