【问题标题】:pthread conditions and process terminationpthread 条件和进程终止
【发布时间】:2013-12-24 17:16:08
【问题描述】:

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

【问题讨论】:

  • “被终止”是否意味着调用了 pthread_cancel?在这种情况下,您应该启用清理处理程序。这是使用互斥锁的用户定义的 rwlock 对象的 POSIX 示例。请参阅示例部分:pubs.opengroup.org/onlinepubs/009695299/functions/…
  • 请显示一些代码。
  • 致吉姆:不,我的意思是当整个过程通过信号终止时,我们假设没有办法拦截该信号来进行任何清理。
  • 致 Pilcrow:代码中还有很多其他不相关的事情,所以整个代码很难在这里发布,但为了澄清场景:进程 #2 创建共享内存段来存储条件及其关联的互斥体并在它们上调用 pthread_cond_init() 和 pthread_mutex_init() (启用 pthread_process_shared 属性)。然后它继续运行做其他事情。进程#1 映射到所述共享内存段,获取指向条件和互斥变量的指针。然后它获取互斥体并调用 pthread_cond_wait() 等待条件。
  • 您是否建议永远不要调用 pthread_cond_destroy 和 pthread_mutex_destroy?我不会泄漏内存或其他资源吗?

标签: c multithreading unix pthreads ipc


【解决方案1】:

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

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

【讨论】:

  • 谢谢。是的,我想我需要使用不同的 IPC 通信方法。由于我正在编写一个库,因此捕获信号可能不是一个好主意,以避免干扰应用程序的信号处理。
【解决方案2】:

另一个选项可能是在调用 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);

【讨论】:

    【解决方案3】:

    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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-02
      • 2018-10-31
      • 2021-04-06
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多