2012-10-12 42 views
5

Tôi có một đối tượng hoạt động trong vòng lặp vô tận. Các main() instantiates đối tượng và gọi phương thức run(). Vì tôi không muốn sử dụng các chủ đề, tôi cần một giải pháp để làm cho đối tượng của tôi ngừng chạy. Dưới đây bạn thấy những gì tôi đã đưa ra.Nhận tín hiệu: Sử dụng chức năng thành viên làm bộ xử lý tín hiệu

struct Foo 
{ 
    void run() 
    { 
     running = 1; 
     while (running) 
      do_something_useful(); 

     std::cout << "Execution stopped." << std::endl; 
    } 

    bool running; 

    void catch_signal(int signal) 
    { 
     std::cout << "Caught signal " << signal << std::endl; 
     if(signal == SIGTERM) 
      running = false; 
    } 

}; 

Như bạn thấy, tôi cần gửi tín hiệu không đồng bộ. Do đó, tôi sử dụng trình xử lý tín hiệu và sigaction. Bên dưới main Tôi có thể tưởng tượng để sử dụng.

int main(int argc, char** argv) 
{ 
    Foo foo; 
    struct sigaction sigIntHandler; 

    boost::function< void (int) > f; 
    f = std::bind1st(
     std::mem_fun(&Foo::catch_signal), &foo); 
    f(5); // this call works 

    sigIntHandler.sa_handler = f;   // compiler complains, "cannot assign ..." 
    sigemptyset(&sigIntHandler.sa_mask); 
    sigIntHandler.sa_flags = 0; 
    sigaction(SIGTERM, &sigIntHandler, NULL); 
    s.run(); 

} 

Những gì tôi mong chờ bây giờ: Chương trình chạy cho đến khi tôi gửi SIGTERM được bắt và sẽ gây ra đối tượng của tôi ngừng lặp đi lặp lại và trở về chính.

Tôi có hai câu hỏi bây giờ:

(a) Trong đoạn mã bạn thấy dòng chữ được đánh dấu bằng "biên dịch phàn nàn", thông điệp giống như

boost::function<void(int)> cannot be converted to __sighandler_t {aka void (*)(int)} 

gì tôi cần phải thay đổi để làm cho công việc này? Tôi nghĩ rằng f giống như void f(int), giống như các chức năng mà trình xử lý tín hiệu nhận được trong một số ví dụ.

(b) Đối với những người bạn thắc mắc "anh chàng đó đang làm gì vậy?": Bạn có lời khuyên nào để giải quyết vấn đề này tốt hơn không?

+0

Chỉ vì tò mò, tại sao bạn không muốn sử dụng đề tài?Mặc dù tôi đã không sử dụng tăng ở tất cả, giả định của tôi nó mong đợi một chức năng gọi lại được cung cấp. – M4rc

+0

Giống như bắt đầu '' Foo :: run() '' trong một luồng, bắt tín hiệu trong '' chính'' và để cho lệnh gọi chính là sth. như '' thread.terminate() ''? Có, sẽ là một khả năng, nhưng tôi nghĩ rằng nó sẽ là quá nhiều cho việc này. –

+0

Đó là một cách chắc chắn. Cái khác mà (trong thiên hướng an thần của tôi) là bạn có thể có cấu trúc với bất kỳ thông tin nào bạn cần, đăng ký nó như một luồng, vì vậy bạn chạy vòng lặp với các hàm chính bình thường trong đó, và trình xử lý tín hiệu đang chạy trên chỉ riêng của nó, sau đó bạn chỉ cần lấy giá trị byref để xem một sự kiện đã xảy ra, và nếu có sự kiện nào và phản hồi thích hợp. – M4rc

Trả lời

7
  • Tôi cần thay đổi gì để thực hiện công việc này? Tôi nghĩ f giống như void f (int), giống như các hàm mà trình xử lý tín hiệu nhận được trong một số ví dụ.

Trình biên dịch phàn nàn về chủng loại, do đó bạn cần phải vượt qua một con trỏ hàm, không phải là một đối tượng kiểu boost::function<void(int)>. Tạo một biến toàn cầu thuộc loại này, và thêm một chức năng trong đó kêu gọi đối tượng này sẽ làm việc:

boost::function<void(int)> myCb; 
void CallCb(int value) 
{ 
    myCb(value); 
} 

int main(int argc, char** argv) 
{ 
    Foo foo; 
    struct sigaction sigIntHandler; 

    myCb = std::bind1st(
     std::mem_fun(&Foo::catch_signal), &foo); 
    f(5); // this call works 

    sigIntHandler.sa_handler = CallCb; 
    sigemptyset(&sigIntHandler.sa_mask); 
    sigIntHandler.sa_flags = 0; 
    sigaction(SIGTERM, &sigIntHandler, NULL); 
    s.run(); 

} 
  • Bạn có bất cứ lời khuyên làm thế nào để giải quyết loại điều tốt hơn?

Không thực sự. Ý tưởng là ok. Tôi sẽ chỉ C++ 11 lambda thay vì

+1

Cảm ơn bạn đặc biệt vì đã chỉ ra rằng '' f'' không phải là một hàm mà là một đối tượng mà tôi không nghĩ đến. –

+0

Bạn có thể đưa ra một ví dụ về cách bạn muốn làm điều đó với một lambda C++ 11? – Azmisov

2

Có rất ít việc bạn có thể thực hiện một cách ổn định trong trình xử lý tín hiệu. Về cơ bản, bạn có thể lưu trữ một giá trị trong một đối tượng có loại là sig_atomic_t. Chèn vào cout, ví dụ, không phải làm việc. Nếu bạn có C++ 11, bạn có thể làm nhiều hơn một chút, sử dụng các loại nguyên tử hoặc hàng rào rõ ràng, nhưng bất kỳ cuộc gọi nào khác vào thư viện chuẩn không bắt buộc phải làm bất cứ điều gì hợp lý. Vì vậy, với tất cả những gì đã nói, những gì bạn có thể làm là viết một hàm (hoặc một hàm miễn phí hoặc một hàm thành viên tĩnh (nhưng có một vấn đề nhỏ ở đây với liên kết C++: chính thức là một hàm thành viên tĩnh sẽ không hoạt động , nhưng trong thực tế nó luôn luôn)) gọi hàm thành viên, lần lượt đặt running thành false (giả sử bạn đã thay đổi loại running thành sig_atomic_t).

Các vấn đề liên quan