2015-05-02 6 views
3

Мне сложно сконструировать основной рабочий процесс моего приложения, используя потоки и сигналы.C++, сигнал и потоки

Моя цель - иметь основной поток, сигналы отвлечения и другие темы, периодически делающие материал (фактически используя датчики на малине pi и сохраняя извлеченные данные). Мне нужна возможность закрыть программу чистым способом, т. Е. Дождаться, что датчик закончит запись данных (если они есть, когда сигнал возникнет) перед закрытием. Я использую 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 секунды .. и это не похоже на чистый способ сделать это. Другое решение, отправляющее сигналы в потоки, позволяет мне просто заставить мой поток «спать»; но снова у меня нет элементов управления, чтобы сообщить потоку завершить его действие до завершения.

Заранее благодарен!

ответ

4

Операции с мьютексом запрещены в обработчике сигналов. Вы можете разделить 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) В основной нити может быть заменена любая функция, прерываемая сигналами.

+0

Спасибо за четкий ответ! – Vuzi

0

Обычный шаблон предназначен для блокировки сигналов для всех рабочих потоков, за исключением специального потока, используемого для обработки сигналов.

Смежные вопросы