【发布时间】:2010-11-11 14:16:22
【问题描述】:
我正在编写一个使用共享内存和 ipc 信号量的程序。有一个主服务器进程创建共享内存和信号量。任何数量的客户端进程都可以附加到共享内存并在允许时对其进行读写。信号量提供阻塞机制来控制读取和写入。一切正常,除非我尝试终止客户端。访问共享内存的信号量块位于线程中,并且在进程终止时,我无法释放信号量块,因此线程正确退出。我该怎么办?这是针对 Linux 的。
具体来说,有一个 shm 和两个 sem。第一个 sem 阻止写入,第二个阻止读取。当客户端有东西要写时,它会等待 write sem 为 0,然后将其设置为 1,写入,然后将 read sem 设置为 0,这会释放等待的服务器以读取客户端写入的内容。一旦读取,服务器将 write sem 设置回 0,并且下一个客户端开始写入。它挂在读取 sem 为 0 时释放的 semop 调用上。这个 semop 调用在一个线程中,我需要弄清楚如何在让主线程终止之前正确退出该线程。
这是我想做但不起作用的示例(睡眠假装是挂起的 semop 调用):
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void termination_handler (int signum) {
printf( "Got Signal\n" );
}
void *threadfunc( void *parm ) {
struct sigaction action;
action.sa_handler = termination_handler;
sigemptyset( &action.sa_mask );
action.sa_flags = 0;
sigaction( SIGUSR1, &action, NULL );
printf("Thread executing\n");
sleep( 100 ); // pretending to be the semaphore
pthread_exit( NULL );
}
int main() {
int status;
pthread_t threadid;
int thread_stat;
status = pthread_create( &threadid, NULL, threadfunc, NULL );
if ( status < 0) {
perror("pthread_create failed");
exit(1);
}
sleep( 5 );
status = pthread_kill( threadid, SIGUSR1 );
if ( status < 0 )
perror("pthread_kill failed");
status = pthread_join( threadid, (void *)&thread_stat );
if ( status < 0 )
perror("pthread_join failed");
exit( 0 );
}
【问题讨论】:
-
请详细说明“无法释放信号量块”的含义。为什么?
-
所以,抛开线程终止问题不谈,真正的问题是为什么你要阻塞这么长时间等待共享内存访问。据推测,客户端正在等待服务器将 write sem 设置回他们可以解除阻塞的位置。服务器是在执行一些长时间的任务,还是设计中可能存在一些未诊断的死锁问题?
-
好吧,进一步阐述。逻辑或等待期没有问题。每个客户端也有一个挂起的 shm,直到服务器向该进程 shm 写入一些内容,并且服务器有一个挂起的 shm,直到任何客户端向该进程 shm 写入一些内容。所以你可以看到,当什么都没有发生时,所有的客户端和服务器只是坐等。我实际上正在研究使用标准输入或内存队列。与其他方法相比,这种原始方法似乎过于复杂。
-
啊,情节变厚了。 :) FWIW,我认为 shm 是一个 PITA,除了最关键的任务之外,在这种情况下你等待了很多。如果您有重新编码的奢侈,Posix MQ 在这里似乎是一个不错的选择。每一方都可以将数据写入队列而不会阻塞,并且可以在读取方使用 mq_notify() 之类的东西。在不知道应用程序的详细信息(我怀疑还有更多)的情况下,它简化了许多事情。
-
我想我实际上会使用管道并只处理标准文件描述符。玩弄它,它做得很好,而且非常简单。感谢所有的帮助和投入。如果您对管道有任何异议,请告诉我,我希望这是我最后一次重新编码!
标签: c linux ipc pthreads semaphore