C 如何终止正在等待信号量操作的线程

C 如何终止正在等待信号量操作的线程,c,linux,ipc,pthreads,semaphore,C,Linux,Ipc,Pthreads,Semaphore,我正在为ipc编写一个使用共享内存和信号量的程序。有一个主服务器进程创建共享内存和信号量。任何数量的客户端进程都可以连接到共享内存,并在允许时对其进行读写。信号量提供阻塞机制来控制读写。除了当我试图终止一个客户时,一切正常。访问共享内存的信号量块位于线程中,在进程终止时,我无法释放信号量块以便线程正确退出。我该怎么办?这是针对Linux的 具体来说,有一个shm和两个SEM。第一个sem阻止写入,第二个sem阻止读取。当客户端有要写的内容时,它会等待write sem为0,然后将其设置为1,写入

我正在为ipc编写一个使用共享内存和信号量的程序。有一个主服务器进程创建共享内存和信号量。任何数量的客户端进程都可以连接到共享内存,并在允许时对其进行读写。信号量提供阻塞机制来控制读写。除了当我试图终止一个客户时,一切正常。访问共享内存的信号量块位于线程中,在进程终止时,我无法释放信号量块以便线程正确退出。我该怎么办?这是针对Linux的

具体来说,有一个shm和两个SEM。第一个sem阻止写入,第二个sem阻止读取。当客户端有要写的内容时,它会等待write sem为0,然后将其设置为1,写入,然后将read sem设置为0,这将释放等待服务器以读取客户端所写的内容。一旦读取,服务器将write sem设置回0,行中的下一个客户机开始写入。它挂起一个semop调用,该调用在read sem为0时释放。这个semop调用在一个线程中,在让主线程终止之前,我需要弄清楚如何正确退出该线程

下面是一个我想做但不起作用的示例(睡眠假装是挂起的semop呼叫):

#包括
#包括
#包括
#包括
#包括
#包括
无效终止处理程序(int信号){
printf(“获取信号”);
}
void*threadfunc(void*parm){
结构动作;
action.sa_handler=终止_handler;
sigemptyset(和action.sa_mask);
action.sa_标志=0;
sigaction(SIGUSR1,&action,NULL);
printf(“线程执行\n”);
睡眠(100);//假装是信号灯
pthread_exit(NULL);
}
int main(){
智力状态;
pthread_t threadid;
int-thread_-stat;
状态=pthread_create(&threadid,NULL,threadfunc,NULL);
如果(状态<0){
perror(“pthread_创建失败”);
出口(1);
}
睡眠(5);
状态=pthread_kill(threadid,SIGUSR1);
如果(状态<0)
perror(“pthread_kill失败”);
状态=pthread_join(threadid,(void*)和thread_stat);
如果(状态<0)
perror(“pthread_join失败”);
出口(0);
}

他说,这是针对Linux的

如果你能准确地说出你是怎么做的,那将是非常有用的。我假设您正在扫描等待或扫描时间等待中阻塞。如果您的线程在那里阻塞,并且您想中断它,那么可以使用pthread_kill

pthread_kill(blocking_thread_id, SIGUSR1);
当然,您需要设置适当的信号处理程序(man sigaction)来捕获SIGUSR1,并且需要检查EINTR的sem_wait()返回代码,在这种情况下,您可以在知道被中断且未获得锁的情况下执行任何您想执行的操作


在使用进程的情况下,您只需使用kill()而不是pthread_kill()来提供进程id。(很抱歉,最初我误读了,以为您使用的是线程)

根据您的环境,您可能只能尝试使用带有超时的信号量。每次超时后,检查是否请求关闭线程,然后简单地放弃并关闭。

我有两个半答案供您参考。:)

首先,您的示例代码适用于我(在Linux上):pthread_kill成功地
EINTR
在大约五秒钟后按预期中断工作线程的睡眠,如一些printf所示,并记住了睡眠的返回值。AFAICT,如果你想用信号中断一个特定的线程,你已经完成了

第二步,尝试
SEM\u UNDO
。这个标志可以在sembuf参数semop中传递的sem_flg成员中设置,顾名思义,它将在进程终止时撤消信号量调整。IIUC,当你杀死一个客户端时,该客户端会不适当地锁定一个信号量
SEM_UNDO
就是针对这种情况而制定的


最后,请恕我直言,您是否在这里颠倒了信号量的逻辑?当我阅读您的问题时,semval为零表示“资源空闲”,semval为1表示“资源锁定”(引用:“…[客户端]等待写入sem为0,然后将其设置为1,写入…”)。但是,如果两个或多个写客户机正在等待SysV sem降到零,那么当发生这种情况时,它们将一起被释放。这是一个相当令人不快的竞争条件,至少可能会导致意外的信号量减少和增加。

如果受保护区域上的操作可能持续太长时间,那么使用阻塞互斥体/信号量可能不是最好的主意

您可以通过将读写请求放入队列(例如,链表)来解决此问题,让队列中的第一个在受保护区域上操作,并在进入该区域后将其从列表中删除

在只读操作的情况下,只要第一个操作是只读的,您就可以访问进入保护区域的其他读取。当第一个操作是写操作时,受保护区域在允许其访问之前必须为空

列表修改必须由互斥锁(或类似的东西)保护,但这几乎是固定时间,您可能需要为此付费

当线程位于队列中时,每个线程都有其私有条件变量,您可以使用该变量唤醒它们中的任何一个。条件变量也必须由互斥锁保护。您可以将条件变量、互斥体等存储到一个结构中,并将其放入一个数组或列表中,并与每个线程一起存储线程id,以便很容易找到要唤醒的线程


一旦线程醒来,它首先检查它必须醒来的原因。如果设置了exit标志,则线程知道要退出

请详细说明“无法释放信号量块”的含义。为什么?所以,抛开线程终止问题不谈,真正的问题是为什么要阻塞这么长时间等待线程终止
pthread_kill(blocking_thread_id, SIGUSR1);