boost:asio信号量signal_setソースコードの分析と使用


まずsignalを見てみましょうset.hpp、次のコードが見えます
#include 
#include 

namespace boost {
namespace asio {

/// Typedef for the typical usage of a signal set.
typedef basic_signal_set<> signal_set;

} // namespace asio
} // namespace boost

明らかにsignalを使っていますsetは実際にはベーステンプレートクラスbasic_ですsignal_set<>再ジャンプbasic_signal_set.hpp
コンストラクタ
    explicit basic_signal_set(boost::asio::io_service& io_service) : basic_io_object<SignalSetService>(io_service)

    basic_signal_set(boost::asio::io_service& io_service, int signal_number_1)
    basic_signal_set(boost::asio::io_service& io_service, int signal_number_1, int signal_number_2)
    basic_signal_set(boost::asio::io_service& io_service, int signal_number_1, int signal_number_2, int signal_number_3) : basic_io_object<SignalSetService>(io_service)

3つのコンストラクション関数は、io_を1つ受け入れていることが明らかになった.サービスと信号量の値、唯一の違いは信号量の数が異なることです.最初は、なぜ可変パラメータテンプレートを作らないのか不思議でしたが、もっとよくはありません.次を見ると釈然とします.クラスsignal_setはすでにadd関数を提供して信号量を増加して、ここで関数の数1~3を構築するのはもっと便利なだけで、パラメータテンプレートについては、実際にはまったく必要ありません.
どうして二つ叶えるんだろう
2つの関数:addがセットに信号量removeを追加して信号量を削除
    void add(int signal_number)
    {
        boost::system::error_code ec;
        this->service.add(this->implementation, signal_number, ec);
        boost::asio::detail::throw_error(ec, "add");
    }
    boost::system::error_code add(int signal_number, boost::system::error_code& ec)
    {
        return this->service.add(this->implementation, signal_number, ec);
    }
    void remove(int signal_number)
    boost::system::error_code remove(int signal_number,
    boost::system::error_code& ec)

2つの関数の唯一の違いは,エラーの処理方法b:エラーコードと異常放出であることが容易に分かった.したがって,エラーコードの判定と異常のキャプチャによりエラー処理を行うことができる.我々のプログラムには同期と非同期の2つのモードがあり,同期モードではどちらを使ってもよいが,非同期モードではプログラムが異常を投げ出すことはないので,エラーコードしか使用できない.
クリアとキャンセルの違い
    void clear()
    boost::system::error_code clear(boost::system::error_code& ec)
    void cancel()
    boost::system::error_code cancel(boost::system::error_code& ec)

文字通りの意味から私たちは彼らの違いを感じやすい.清空とは何か、清空はなくなったが、キャンセルはなかったわけではない.(ps:ネーミングだけで推測できる八九離十のコードは、良いコードと言える)コード:clear:コレクション内のすべての信号量をクリア(削除)し、通知キュー内のすべてのイベントを削除し、コレクション自体が空であればエラーを投げ出す.cancel:集合中の信号量を変更せず、信号に関連するすべての動作にエラーコードを投げ出して動作を終了する.
async_wait
template <typename SignalHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler, void (boost::system::error_code, int))
async_wait(BOOST_ASIO_MOVE_ARG(SignalHandler) handler)
{
    // If you get an error on the following line it means that your handler does
    // not meet the documented type requirements for a SignalHandler.
    BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;

    return this->service.async_wait(this->implementation, BOOST_ASIO_MOVE_CAST(SignalHandler)(handler));
}

この関数はsignal_setの主な使用はこの関数に依存します.この関数は、void(boost::system::error_code,int))タイプの関数ハンドルを受け取り、その後、傍受信号が発生したときに呼び出されます.関数の内部実装は、2つの文しかありません.
BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;

関数に対してタイプチェックを行い、このマクロは複雑に書かれていて、しばらく見て、率直に言って、その機能を知っていますが、一つ一つの意味が分からないので、時間を見つけてよくここをドリルしてください.
return this->service.async_wait(this->implementation, BOOST_ASIO_MOVE_CAST(SignalHandler)(handler));

最後に、下位インタフェースにタスクの完了を再帰的に依頼します.
使用例
//
//  main.cpp
//  AsioServer
//
//  Created by shiyi on 2016/12/10.
//  Copyright © 2016  shiyi. All rights reserved.
//

#include 
#include 
#include 
#include 

using namespace boost;

void signal_handler(const boost::system::error_code& err, int signal)
{
    switch (signal) {
        case SIGINT:
            std::cout << "SIGNINT" << std::endl;
            break;
        case SIGTERM:
            std::cout << "SIGNTERM" << std::endl;
            break;
        default:
            break;
    }
}

int main(int argc, const char * argv[]) {

    asio::io_service service;

    asio::signal_set sigset(service, SIGINT, SIGTERM);
    sigset.async_wait(signal_handler);

    boost::system::error_code ec;
    service.run(ec);
    if(ec)
    {
        std::cout << boost::system::system_error(ec).what() << std::endl;
    }
    std::cout << "End" << std::endl;

}