拥有以下源代码:
#define THREAD 32
#define QUEUE 300
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include "threadpool.h"
struct fparam {
int no;
};
int tasks = 0, done = 0;
pthread_mutex_t lock;
int exit_me(){
pthread_mutex_lock(&lock);
tasks--;
pthread_mutex_unlock(&lock);
return 0;
}
void dummy_task(void *arg) {
struct fparam *args = arg;
pthread_mutex_lock(&lock);
done++;
pthread_mutex_unlock(&lock);
printf("Thread INDEX: %d started.\n",args->no);
exit_me();
}
int main()
{
int t, result;
threadpool_t *pool;
struct fparam push_args;
pthread_mutex_init(&lock, NULL);
pool = threadpool_create(THREAD, QUEUE, 0);
fprintf(stderr, "Pool started with %d threads and "
"queue size of %d\n", THREAD, QUEUE);
for (t = 0;t < 2000; t++){
push_args.no = t;
result = threadpool_add(pool, &dummy_task, (void *)&push_args, 0);
if (result == 0){
pthread_mutex_lock(&lock);
tasks++;
pthread_mutex_unlock(&lock);
} else {
printf("Something went wrong with thread: %d\n", t);
}
while(tasks >= QUEUE); // do nothing until tasks running is less than max queue.
}
while(tasks >= 1);
return 0;
}
我正在使用https://github.com/mbrossard/threadpool池实现。
一切看起来都不错,但在检查传递给虚拟函数的t
参数时,我可以看到重复:
Thread INDEX: 1998 started.
Thread INDEX: 1999 started.
Thread INDEX: 1999 started.
Thread INDEX: 1974 started.
Thread INDEX: 1979 started.
Thread INDEX: 1979 started.
Thread INDEX: 1978 started.
Thread INDEX: 1979 started.
Thread INDEX: 1979 started.
我认为代码中没有任何竞争条件,因为在函数内声明了fparam
结构。
有什么想法或建议吗?
答案 0 :(得分:2)
是的,您的push_args
正在遭遇竞争状况。虽然每个线程都获得了您传入的参数的副本,但您执行该操作的方式意味着每个线程都会获得相同的值(指针)。
主线程不断修改背后的指针,而不是启动新线程,但线程本身正在启动并使用它。
以下列顺序为例:
现在两个线程都使用ID为2。
如果你想这样做,你可能需要等到每个线程都制作了这个ID值的本地副本,然后再在main
中进行修改。
另一种方式是&#34;自动&#34;通过将它作为参数本身(而不是指向它的指针)传递给线程一个本地副本,如:
result = threadpool_add(pool, &dummy_task, (void *)t, 0);
这可确保每个线程都收到t
的本地化副本,就像调用时一样。您只需将其从void*
投回int
。
如果你不能使用一个能够与指针进行强制转换的简单变量,并且你不想等到每个线程在开始下一个之前制作了本地副本,你需要分开传递的物品。
实现此目的的一种方法是拥有项目的数组(在您的情况下为结构)并将它们传递给等效的线程。例如,您可以执行以下操作:
static struct payload items[100];
for (int i = 0; i < 100; i++) {
items[i].t = i;
result = threadpool_add(pool, &dummy_task, (void *)(&items[i]), 0);
// check result.
}
这在内存上有点贵,但它解决了竞争条件的问题而无需序列化线程创建。
答案 1 :(得分:0)
我实际上是成功的。请检查以下内容,并建议是否有其他错误。
int main()
{
int t, result;
threadpool_t *pool;
struct fparam *push_args = NULL;
pthread_mutex_init(&lock, NULL);
pool = threadpool_create(THREAD, QUEUE, 0);
fprintf(stderr, "Pool started with %d threads and "
"queue size of %d\n", THREAD, QUEUE);
for (t = 0;t < 2000; t++){
push_args = (struct fparam*)malloc(sizeof *push_args);
push_args->no = t;
result = threadpool_add(pool, &dummy_task, push_args, 0);
if (result == 0){
pthread_mutex_lock(&lock);
tasks++;
pthread_mutex_unlock(&lock);
} else {
printf("Something went wrong with thread: %d\n", t);
}
while(tasks >= QUEUE); // do nothing until tasks running is less than max queue.
}
while(tasks >= 1);
free(push_args);
return 0;
}