简体   繁体   English

C ++,信号和线程

[英]C++, signal and threads

I'm having some hard time designing the main workflow of my application, using threads and signals. 我在使用线程和信号设计应用程序的主要工作流时遇到了一些困难。

My goal here is to have a main thread, catching signals, and n other threads doing stuff periodically (actually using sensors on a raspberry pi, and saving retrieved data). 我的目标是要有一个主线程,捕获信号以及n个其他线程定期执行操作(实际上是在树莓派上使用传感器,并保存检索到的数据)。 I want the ability to close the program in a clean way, ie wait that a sensor has finished writing data (if they are when the signal occur) before closing it. 我希望能够以一种干净的方式关闭程序,即在关闭传感器之前等待传感器完成数据写入(如果是在发生信号时)。 I'm using C++ 11. 我正在使用C ++ 11。

For now, I have this example : 现在,我有这个例子:

#include <iostream>
#include <thread>
#include <csignal>
#include <mutex>

#define NUM_THREAD 3;

static volatile int stop = 0;     // If the threads needs to stop
std::mutex m;                     // Mutex

void threadHandle(int tid) {
    while(1) {
        std::cout << "Launched by thread " << tid << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(2));
        std::cout << "I have sleep well " << tid << std::endl;

        m.lock();
        if(stop) {
            std::cout << "Thread " << tid << " needs to stop" << std::endl;
            m.unlock();
            break;
        }
        m.unlock();
    }
}

void signalHandler(int signum) {
    m.lock();
    std::cout << "Signal " << signum << " received" << std::endl;
    stop = 1;
    m.unlock();
}

int main() {
    std::thread t[NUM_THREAD];
    std::signal(SIGINT, signalHandler);

     //Launch a group of threads
     for (int i = 0; i < NUM_THREAD; i++) {
         t[i] = std::thread(call_from_thread, i);
     }

     std::cout << "Launched from the main\n";

     for (int i = 0; i < NUM_THREAD; i++) {
         t[i].join();
     }

     return 0;
}

My stop value is volatile only because I'm using it inside a signal handler. 我的止损值是可变的,仅因为我在信号处理程序中使用了它。 Should I use an std::atomic_int to ensure atomic calls to my signal value? 我应该使用std :: atomic_int来确保原子调用信号值吗? Is the mutex really necessary? 互斥量真的有必要吗? Or more generally, is this a good way to achieve what I want ? 或更笼统地说,这是实现我想要的一个好方法吗?

Another problem I could have, is that some sensors may have a waiting time between measures really long (like 2 or 3 hours), so I would be in need to check the stop value every 2 or 3 seconds.. and it doesn't feel really like the clean way to do it. 我可能遇到的另一个问题是,某些传感器在两次测量之间的等待时间可能会很长(例如2或3个小时),因此我需要每2或3秒检查一次停止值..感觉真的很干净。 The other solution, sending signals to the threads, allow me to simply make my thread "sleep"; 另一种解决方案是向线程发送信号,使我可以简单地使线程“休眠”。 but again I have no controls to tell the thread to complete its action before terminating. 但是同样,我没有控件可以告诉线程在终止之前完成其操作。

Thanks in advance ! 提前致谢 !

Operations on mutex are disallowed in signal handler. 在信号处理程序中不允许对互斥锁进行操作。 You can split stop variable into two: 您可以将stop变量分为两个:

  1. stop_main , which is set in signal handler, and is waited in the main thread. stop_main ,在信号处理程序中设置,并在主线程中等待。 Because signal handler is executed in the context of the main thread, it is sufficient to declare it volatile (or std::atomic ). 因为信号处理程序是在主线程的上下文中执行的,所以声明它为volatile (或std :: atomic )就足够了。
  2. stop_threads , which is set in the main thread, and is waited by the other ones. stop_threads ,它在主线程中设置,并由其他线程等待。 The most suitable type for this variable is std::condition_variable . 最适合此变量的类型是std :: condition_variable This type also helps in your waiting for a long time. 这种类型也有助于您等待较长时间。

Something like this: 像这样:

std::atomic<int> stop_main = 0;
std::condition_variable stop_threads;
std::mutex m; // protects 'stop_threads'

void threadHandle(int tid)
{
    while(1)
    {
        /* .. do something .. */

        std::unique_lock<std::mutex> l(m);
        if(stop_threads.wait_for(l, std::chrono::hours(2)) ==
            std::cv_status::no_timeout) break;
    }
}
void signalHandler(int signum)
{
    stop_main.store(1);
}
int main()
{
    std::thread t[NUM_THREAD];
    std::signal(SIGINT, signalHandler);

    for (int i = 0; i < NUM_THREAD; i++) {
        t[i] = std::thread(threadHandle, i);


    while(!stop_main.load())
    {
        /* Some workload may be here */
        sleep(10); // Signals will interrupt this function.
    }

    stop_threads.notify_all();

    for (int i = 0; i < NUM_THREAD; i++) {
        t[i].join();

    return 0;
}

I'm uncertain, whether c++ garantees signals delivery to the main thread, not to the others. 我不确定,c ++是否保证将信号传递给主线程,而不传递给其他线程。 Otherwise you need to block signals in other threads. 否则,您需要阻止其他线程中的信号。

sleep(10) in the main thread may be replaced with any function interruptible by the signals. 主线程中的sleep(10)可以被信号可中断的任何功能所代替。

通常的模式是为所有工作线程阻塞信号,但用于信号处理的特殊线程除外。

The main process is deadlocked when signal handler is called by a second signal interrupt ( m.lock() in your signalHandler() ). 当第二个信号中断( m.lock()中的m.lock() )调用信号处理程序时,主进程处于死锁状态。

Try this code with interrupt counting and locking just for the first one: 尝试使用此代码,仅对第一个代码进行中断计数和锁定:

    void signalHandler(int signum) {

        std::cout << "Signal " << signum << " received" << std::endl;

        // avoid double signal deadlocking
        static volatile unsigned intCounter = 0;
        intCounter++;
        if (intCounter == 1)
        {
            // just the first signal will lock
            m.lock();
            stop = true;
            m.unlock();
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM