在多线程程序中处理信号

Handling signals in multithreaded program

提问人:Mattia Piras 提问时间:11/8/2023 更新时间:11/8/2023 访问量:58

问:

我正在编写一个多线程程序作为课程的项目,我写了所有内容,我只需要向某人询问一些我不确定我是否做对的事情。该程序管理一个哈希表,它由 python 中的服务器、2 个 C 客户端和一个主程序(仍在 C 中)制作。服务器通过套接字与客户端通信,客户端从文件中读取文本,并将文本行发送到服务器,使用管道将它们发送到主程序,对它们进行标记并将它们插入哈希表中,或者读取它们的值(如果存在)。

现在,该项目指定所有信号必须由特定线程处理,特别是:

  • 当它收到 SIGINT 时,它必须打印哈希表中元素的计数
  • 当它被接收到时SIGUSR1它必须释放哈希表并创建一个新表
  • 当它被接收到SIGTERM时,它必须等待所有其他线程加入(释放内存)并终止程序。

我处理了这个问题,屏蔽了主信号中的所有信号,并在启动信号处理程序时重新调整它们,然后它在 while 循环中调用 sigwait(),它像这样处理信号:

while(1){
        sigwait(&mask,&signum);
        if(signum==SIGTERM){
            logging_log(arg->log,"INFO","[HANDLER] received SIGTERM");
            xpthread_join(*arg->capolet,NULL,here);
            xpthread_join(*arg->caposc,NULL,here);
            fprintf(stdout,"Elements in Hash_Table:%d\n",*(arg->Hash_elem));
            list_destroy(*arg->list);
            hdestroy();
            logging_log(arg->log,"INFO","[HANDLER] exiting");
            pthread_exit(NULL);
        }
        if(signum == SIGINT){
            // logging_log(arg->log,"INFO","[HANDLER] received SIGINT");
            fprintf(stderr,"Elementi nella tabella: %d\n",*(arg->Hash_elem));
        }
        if(signum==SIGUSR1){
            write_lock(arg->hash_control);
                // logging_log(arg->log,"INFO","[HANDLER] received SIGUSR1");
                list_destroy(*arg->list);
                *arg->list = NULL;
                *(arg->Hash_elem)=0;
                hdestroy();
                xhcreate(Num_elem,here);
            write_unlock(arg->hash_control);
        }
    }

现在请注意,所有名称前带有 x 的函数(如“xpthread_join()”)都只是处理错误的库函数,我使用链表来记录我在插入 Hash 表时分配的所有内存块的计数。此外,“logging_log”是一个函数,它写入(使用互斥锁)日志文件,在结构 (arg->log) 中定义。

以下是我的问题:

  1. 有一个小的时间窗口,所有信号都在所有程序中被屏蔽(从主屏蔽它们,直到信号处理程序解除屏蔽),这是否是一个问题?我能做得更好吗?
  2. 例如,使用专门的处理程序(带有 sigaction)来处理值的打印会更好吗?
  3. 由于程序是多线程的,我创建了一个在哈希表中读取或写入的线程之间共享的结构“Hash_control”,并且我制作了一些函数来处理“读取器-写入器问题”,当接收SIGUSR1信号处理程序时,必须与其他线程争夺对哈希表的访问,这很好吗?(我想不是)

如果有人告诉我我做错了什么以及我可以做得更好,那就太棒了,但请注意,我必须尊重上面的细节。

谢谢

C 多线程 信号

评论

1赞 John Bollinger 11/8/2023
请注意,术语“信号处理程序”具有约定俗成的含义,与您使用它的方式不一致。我有点困惑,直到我发现你在谈论(我认为)一个专门用于同步处理信号的线程。
0赞 Mattia Piras 11/8/2023
当你说不一致时,你是什么意思?
0赞 John Bollinger 11/8/2023
我所说的“不一致”是指当我说“信号处理程序”时,我的意思是与你看起来不同的东西(异步信号处理函数)(同步信号处理线程)。
0赞 Mattia Piras 11/8/2023
谢谢你的回答
0赞 Andrew Henle 11/8/2023
启动信号处理程序时你究竟是如何启动信号处理程序的。“信号处理程序”短语具有特定的含义 - “信号处理程序”是在接收到信号并使用 或 安装/配置信号时调用的函数。如果您要启动一个单独的线程来调用 ,那就不同了。signal()sigaction()sigwait()

答:

1赞 John Bollinger 11/8/2023 #1
  1. 有没有一个问题,有一个小的时间窗口,所有信号都被屏蔽在所有程序中(从主屏蔽它们开始, 直到信号处理程序揭开它们的面纱)?我能做得更好吗?

不多。如果信号到达进程,而该进程被所有线程阻塞,则该进程将变为挂起状态。如果它被解锁,它将被交付。但是,每个信号一次只能有一个实例处于挂起状态,因此,如果一连串信号非常接近,那么一些信号可能会丢失。即使信号没有被阻塞,这种情况也可能显现出来。

  1. 例如,使用专门的处理程序(带有 sigaction)来处理值的打印会更好吗?

您描述的信号处理程序应该快速运行,并且它们只能调用异步信号安全函数。不过,该函数不是异步信号安全的。我倾向于猜测您想在那里使用的其他一些函数也不是异步信号安全的,因此您可能最好使用同步信号处理,例如您已经实现的。fprintf()write()

  1. 由于该程序是多线程的,因此我创建了一个结构“Hash_control”,在读取或写入哈希的线程之间共享 表,我做了一些函数来处理“读取器-写入器 问题是,当接收SIGUSR1信号处理程序时, 必须与其他线程争夺对哈希表的访问?(一世 假设不是)

不,不是。即使您同步处理,您也希望您的处理速度很快。如果您的处理程序线程可能无限期阻塞,这是一个相当大的问题。一种替代方法是,它改为设置标志或将事件排入队列,或者使用其他类似的机制向其他线程指示,当机会到来时,应执行请求的操作。

根据 (2),这种方法也是一种异步接收信号的方法。如果处理程序仅注册操作请求,而不是直接执行适当的操作,那么这将解决我上面描述的问题。


另请注意,如果您确实在信号处理线程中取消阻止所有支持的信号,则存在一个信号到达而该线程已经在处理另一个信号的潜在问题。您可能需要考虑代替 ,因为前者允许您在等待时暂时取消阻止信号。但是,请仔细阅读其文档 - 在这种情况下,您将需要注册信号处理函数,即使它们什么都不做。sigsuspend()sigwait()