首页 > 解决方案 > 处理 SIGTERM 后无法使用条件变量正确退出子进程

问题描述

我创建了一个子进程,我正在处理SIGTERM从父进程发送的消息。在子进程中,我在一个新线程中等待一个condition_variable 。由函数内部的信号处理程序设置。cvwaitingForWork()cvSIGTERMstopTheWait()

由于某种原因,该stopTheWait()函数无法获取lockwaitingForWork()永远等待并且doTheCleanUp()永远不会被调用。

最后父进程关闭。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable


std::mutex mtx;
std::condition_variable cv;

void stopTheWait(){
    printf("[CHILD] Stopping the wait.. \n\n");
    std::lock_guard<std::mutex> lck(mtx);
    cv.notify_all();
}

void signal_callback_handler(int signum)
{
   printf("[CHILD] Caught signal, trying to stop the wait... %d\n\n",signum);
   stopTheWait();
}

void doTheCleanUp()/* is never called*/ {
    printf("[CHILD] clean up... \n\n");
}

void waitingForWork(){
    printf("[CHILD] wait for ever... \n\n");

    std::unique_lock<std::mutex> lck(mtx);
    cv.wait(lck);
    doTheCleanUp();
    printf("[CHILD] clean Up Done, now end wait... \n\n");
    exit(0);
}


int main()
{
    printf("[PARENT] in parent...\n");
    int pid;
   if ((pid = fork()) < 0) { 
        perror("fork"); 
        exit(1); 
    } 
    
   if (pid == 0) 
    { /* child */
        signal(SIGTERM, signal_callback_handler);
        std::unique_lock<std::mutex> lck(mtx);

        std::thread t1(waitingForWork);
        t1.join();
        
        waitingForWork();
        printf("[CHILD] wait is over...\n\n");
    } 

    else /* parent */
    { /* pid hold id of child */

        sleep(3); /* pause for 3 secs */
        printf("[PARENT] sending SIGTERM\n\n"); 
        kill(pid, SIGTERM); 
        sleep(3);
    } 

   printf("[PARENT] exiting parent...\n");
   sleep(1);
   
   return 0;
}

我看到下面的打印。

在此处输入图像描述

标签: c++multithreadingc++11condition-variablesigterm

解决方案


[support.signal]/3评估是信号安全的,除非它包括以下内容之一:

(3.1) — 对任何标准库函数的调用,除了普通的无锁原子操作和明确标识为信号安全的函数。
...

如果信号处理程序调用包含非信号安全的评估,则它具有未定义的行为。

在信号处理程序中几乎没有什么可以安全地做的。printf,互斥量和条件变量操作一目了然。


推荐阅读