在C中释放struct时立即停止pthread

时间:2013-05-15 01:17:47

标签: c multithreading pthreads

我有一个工作线程处理工作项的队列。我刚刚实现了第二个工作程序来处理worker1中插入的项目。但是,在使用Valgrind时我遇到了一些Invalid reads

我假设这是因为我传递给struct foo的{​​{1}}在主线程中的某个点被释放。基本上worker2()是一个不断更新的结构(malloc / free),但是,我希望struct foo将一些缺少的项插入worker2

我的问题是:只有foo worker2 struct fooNULL是否可以停止处理?并在调用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);
}

2 个答案:

答案 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)

您没有为worker1worker2定义任何终止条件。我认为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)测试。