pthread条件和进程终止

时间:2013-12-07 08:36:44

标签: c multithreading unix pthreads ipc

我有一个进程共享的pthread条件(带有关联的互斥锁)。如果等待此条件的进程(使用pthread_cond_wait()或pthread_cond_timedwait())终止会发生什么?这种情况是否仍可被其他进程使用?

在我的场景中,#1等待条件并终止。进程#2在某个时刻看到它是唯一一个现在使用条件并调用pthread_cond_destroy()。

我所看到的是pthread_cond_destroy()只是挂起。有人遇到过同样的问题吗?

从pthread_cond_destroy()的手册页中可以看出,破坏某些线程仍在等待的条件会导致未定义的行为。在我的情况下,当进程#2调用pthread_cond_destroy()时,没有人在等待,因为等待进程#1被终止,但显然条件本身仍然认为存在等待线程。

有没有解决这个问题的方法?

编辑:

根据请求,我发布了示例程序(我在这里颠倒了p1& p2):

p1.cpp:

#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

struct MyCond {
    pthread_mutex_t m;
    pthread_cond_t c;
};

int main()
{
    pthread_mutexattr_t ma;
pthread_mutexattr_init(&ma);
pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);

pthread_condattr_t ca;
pthread_condattr_init(&ca);
pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_SHARED);

int fd = shm_open("/test_cond_p", O_RDWR|O_CREAT, 0666);
ftruncate(fd, sizeof(MyCond));

MyCond *c = (MyCond *)mmap(NULL, sizeof(MyCond),
    PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
//close (fd);

pthread_mutex_init(&c->m, &ma);
pthread_cond_init(&c->c, &ca);
printf("Inited MyCond, %x\n", c);

puts("Press Enter to continue");
fgetc(stdin);

    int r = pthread_cond_signal(&c->c);
    printf("After pthread_cond_signal, r=%d\n", r);

puts("Before pthread_cond_destroy");
r = pthread_cond_destroy(&c->c);
printf("After pthread_cond_destroy, r=%d\n", r);
r = pthread_mutex_destroy(&c->m);
printf("After pthread_mutex_destroy, r=%d\n", r);

munmap(c, sizeof(MyCond));
shm_unlink("/test_cond_p");

return 0;
}

p2.cpp:

#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>

struct MyCond {
pthread_mutex_t m;
pthread_cond_t c;
};

int main()
{
int fd = shm_open("/test_cond_p", O_RDWR, 0666);

MyCond *c = (MyCond *)mmap(NULL, sizeof(MyCond),
    PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
//close (fd);

pthread_mutex_lock(&c->m);
puts("Before pthread_cond_wait");
int r = pthread_cond_wait(&c->c, &c->m);
printf("After pthread_cond_wait, r=%d\n", r);

munmap(c, sizeof(MyCond));
return 0;
}

首先运行p1,然后运行p2,在它说“在pthread_cond_wait之前”之后,按Ctrl-C它。然后在p1的shell中按Enter键。

起初,我无法重现挂起,但我同时使用pthread_cond_destroy()和pthread_mutex_destroy()来返回EBUSY。

但是如果我们在pthread_cond_destroy()之前调用pthread_cond_signal(),那么挂起就会重现(参见上面的代码)。

3 个答案:

答案 0 :(得分:1)

似乎p2进程正在等待条件变量,因为p1进程没有机会发送ctrl-c终止的通知。正如您和其他人已经提到的那样,pthread条件变量不会“知道”其原始进程终止。

如果您不能使用其他进程间通信功能并且仍然坚持使用共享互斥锁和条件变量,我会考虑捕获信号。

答案 1 :(得分:1)

pthread_cond_destroy的源代码如下:

  

因此,我们可以假定所有仍在访问condvar的侍者都已被唤醒。我们一直等到他们通过减少__wref来确认已经醒来。

因此我们可以在pthread_cond_destroy之前将__wrefs重置为零:

c->c.__data.__wrefs = 0;
r = pthread_cond_destroy(&c->c);

我为您提供了此更改的示例,并且P1完全没有挂起。

请注意,在this commit __wrefs之前被称为__nwaiters。

答案 2 :(得分:0)

在调用pthread_cond_destroy()之前,还有一个选项可能是显式调用pthread_ond_broadcast()

像这样:

r = pthread_cond_broadcast(&c->c);
puts("Before pthread_cond_destroy");
r = pthread_cond_destroy(&c->c);
printf("After pthread_cond_destroy, r=%d\n", r);
r = pthread_mutex_destroy(&c->m);
printf("After pthread_mutex_destroy, r=%d\n", r);