pthread条件和进程终止

问题描述 投票:6回答:3

我有一个进程共享的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(),则挂起会重现(请参阅上面的代码)。

c multithreading unix pthreads ipc
3个回答
1
投票

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

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


1
投票

pthread_cond_destroy的源代码如下:

因此,我们可以假设所有仍在访问condvar的服务员都被唤醒了。我们等到他们已经确认通过递减__wrefs而醒来。

所以我们可以在pthread_cond_destroy之前简单地将__wrefs重置为零:

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

我用这个改变跑了你的样本,P1完成没有挂起。

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


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);
© www.soinside.com 2019 - 2024. All rights reserved.