【问题标题】:C++, signal and threadsC++、信号和线程
【发布时间】:2015-05-02 13:02:18
【问题描述】:

我在使用线程和信号来设计我的应用程序的主要工作流程时遇到了一些困难。

我的目标是有一个主线程,捕捉信号,和其他线程定期做一些事情(实际上使用树莓派上的传感器,并保存检索到的数据)。我希望能够以干净的方式关闭程序,即等待传感器完成写入数据(如果它们是在信号发生时),然后再关闭它。我正在使用 C++ 11。

现在,我有这个例子:

#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;
}

我的停止值是不稳定的,只是因为我在信号处理程序中使用它。我应该使用 std::atomic_int 来确保对我的信号值进行原子调用吗?互斥锁真的有必要吗?或者更一般地说,这是实现我想要的好方法吗?

我可能遇到的另一个问题是,某些传感器在测量之间的等待时间可能非常长(例如 2 或 3 小时),因此我需要每 2 或 3 秒检查一次停止值......感觉不是很干净的方法。另一种解决方案是向线程发送信号,让我可以简单地让我的线程“休眠”;但我再次无法控制告诉线程在终止之前完成其操作。

提前致谢!

【问题讨论】:

    标签: c++ multithreading c++11 signals


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      信号处理程序中不允许对互斥体进行操作。您可以将stop 变量拆分为两个:

      1. stop_main,在信号处理器中设置,在主线程中等待。因为信号处理程序是在主线程的上下文中执行的,所以声明它volatile(或std::atomic)就足够了。
      2. stop_threads,在主线程中设置,被其他线程等待。这个变量最适合的类型是std::condition_variable。这种类型也有助于您长时间等待。

      类似这样的:

      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;
      }
      

      我不确定,C++ 保证是否向主线程发出信号,而不是向其他线程。否则需要阻塞其他线程中的信号。

      主线程中的sleep(10) 可以替换为任何可被信号中断的函数。

      【讨论】:

        【解决方案3】:

        当第二个信号中断(signalHandler()中的m.lock())调用信号处理程序时,主进程是deadlocked

        试试这个代码,只为第一个中断计数和锁定:

            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();
                }
            }
        

        【讨论】:

          猜你喜欢
          • 2013-12-12
          • 2018-06-04
          • 2012-09-14
          • 2011-02-04
          • 2017-03-25
          • 2015-07-06
          • 1970-01-01
          • 1970-01-01
          • 2010-12-06
          相关资源
          最近更新 更多