我有一个工作线程处理工作项的队列。我刚刚实现了第二个工作程序来处理worker1
中插入的项目。但是,在使用Valgrind时我遇到了一些Invalid reads
。
我假设这是因为我传递给struct foo
的{{1}}在主线程中的某个点被释放。基本上worker2()
是一个不断更新的结构(malloc / free),但是,我希望struct foo
将一些缺少的项插入worker2
。
我的问题是:只有foo
worker2
struct foo
,NULL
是否可以停止处理?并在调用create_foo()
时重新开始?我不确定用线程将缺少的项插入foo
的最佳方法是什么?任何反馈都表示赞赏。
//canonical form
//producer
void push_into_queue(char *item)
{
pthread_mutex_lock(&queueMutex);
if (workQueue.full) { // full }
else
{
add_item_into_queue(item);
pthread_cond_signal(&queueSignalPush);
}
pthread_mutex_unlock(&queueMutex);
}
}
// consumer1
void *worker1(void *arg)
{
while (true) {
pthread_mutex_lock(&queueMutex);
while (workQueue.empty)
pthread_cond_wait(&queueSignalPush, &queueMutex);
item = workQueue.front; // pop from queue
add_item_into_list(item);
pthread_cond_broadcast(&queueSignalPop);
pthread_mutex_unlock(&queueMutex);
}
return NULL;
}
pthread_create(&thread1, NULL, (void *) &worker, NULL);
// consumer2
void *worker2(void *arg)
{
my_struct *foo = (my_struct *) arg;
while (true) {
pthread_mutex_lock(&queueMutex);
while (list.empty)
pthread_cond_wait(&queueSignalPop, &queueMutex);
for (i = 0; i < list.size; i++)
insert_item_into_foo(list[i].item, foo);
pthread_cond_broadcast(&queueSignalPop);
pthread_mutex_unlock(&queueMutex);
}
return NULL;
}
void create_foo()
{
my_struct *foo = calloc(10, sizeof(my_struct));
pthread_create(&thread2, NULL, (void *) &worker2, foo);
}
void free_foo()
{
pthread_mutex_lock(&queueMutex);
int i;
for (i=0; i<5; i++)
free(foo[i].list->string);
free(foo[i].list);
free(foo);
pthread_mutex_unlock(&queueMutex);
}
答案 0 :(得分:1)
使foo全局并在循环中添加一些指针检查 下次调用create_foo时,它将重新启动线程。
my_struct *foo = NULL;// consumer2 void *worker2(void *arg) {
while (true) { if ( fool == NULL ) return; pthread_mutex_lock(&queueMutex); while (list.empty) pthread_cond_wait(&queueSignalPop, &queueMutex); for (i = 0; i < list.size; i++) insert_item_into_foo(list[i].item, foo); pthread_cond_broadcast(&queueSignalPop); pthread_mutex_unlock(&queueMutex); } return NULL;
}
答案 1 :(得分:1)
您没有为worker1
和worker2
定义任何终止条件。我认为foo
的eol可以被认为是这样的。这意味着两个工作人员必须通过拥有对foo
的引用来监控foo **
的存在(即void *worker2(void *arg)
{
my_struct **foo = (my_struct **) arg;
while(true) {
pthread_mutex_lock(&queueMutex);
while (list.empty)
pthread_cond_wait(&queueSignalPop, &queueMutex);
if (NULL == *foo)
break;
for (i = 0; i < list.size; i++)
insert_item_into_foo(list[i].item, *foo);
pthread_cond_broadcast(&queueSignalPop);
pthread_mutex_unlock(&queueMutex);
}
free(foo);
return NULL;
}
void create_foo()
{
my_struct *foo = calloc(10, sizeof(my_struct ));
my_struct **foo_ptr = malloc(1, sizeof(my_struct *));
*foo_ptr = foo;
pthread_create(&thread2, NULL, (void *) &worker2, foo_ptr);
// more work with foo
}
)。
foo
请注意,必须以某种方式将free_foo
分配给另一个变量,以便在create_foo
中可以访问(您的代码会假设这一事实而不会明确地显示它 - 因此我在{{1}末尾的注释}})。
使用上面的代码,worker2
的每个实例都拥有一个指向其整个生命周期的指针,并且必须在退出之前处理它。
或许更好的解决方案是将结构传递给thread2
,其中包含foo
指针,以及指示该指针是否仍然有效的标志。您可以在struct ad lib中添加线程所需的任何其他信息。
struct th2_data {
enum {RUNNING, TERMINATING} state;
my_struct *foo;
};
然后分配该结构的一个实例,将其初始化为{RUNNING, foo}
,并将其传递给thread2
。在某处保留其地址的副本,以便能够将TERMINATING
状态发送到thread2
。实际上,正如您在评论中提到的那样,您必须用if (NULL == *foo)
替换thread2中的if (foo.state == TERMINATING)
测试。