首页 > 解决方案 > 通过安装信号处理程序关闭多线程应用程序

问题描述

在下面的代码中,我创建了一个玩具类,它有一个线程写入队列,而另一个线程从该队列读取并将其打印到stdout. 现在,为了彻底关闭系统,我为SIGINT. 我期待信号处理程序设置std::atomic<bool>变量stopFlag,这将导致threadB将毒丸(哨兵)推到遇到的队列中,该队列threadA将停止。

class TestClass
{
public:

    TestClass();
    ~TestClass();
    void shutDown();

    TestClass(const TestClass&) = delete;
    TestClass& operator=(const TestClass&) = delete;


private:
    void init();
    void postResults();
    std::string getResult();
    void processResults();

    std::atomic<bool> stopFlag;

    std::mutex outQueueMutex;
    std::condition_variable outQueueConditionVariable;
    std::queue<std::string> outQueue;

    std::unique_ptr<std::thread> threadA;
    std::unique_ptr<std::thread> threadB;
};

void TestClass::init()
{
    threadA = std::make_unique<std::thread>(&TestClass::processResults, std::ref(*this));
    threadB = std::make_unique<std::thread>(&TestClass::postResults, std::ref(*this));
}

TestClass::TestClass():
    stopFlag(false)
{
    init();
}

TestClass::~TestClass()
{
    threadB->join();
}

void TestClass::postResults()
{
    while(true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(2000));
        std::string name = "ABCDEF";
        {
            std::unique_lock<std::mutex> lock(outQueueMutex);
            outQueue.push(name);
            outQueueConditionVariable.notify_one();
        }
        if(stopFlag)
        {
            /*For shutting down output thread*/
            auto poisonPill = std::string();
            {
                std::unique_lock<std::mutex> lock(outQueueMutex);
                outQueue.push(poisonPill);
                outQueueConditionVariable.notify_one();
            }
            threadA->join();
            break;
        }
    }
}

void TestClass::shutDown()
{
    stopFlag = true;
}

std::string TestClass::getResult()
{
    std::string result;
    {
        std::unique_lock<std::mutex> lock(outQueueMutex);
        while(outQueue.empty())
        {
            outQueueConditionVariable.wait(lock);
        }
        result= outQueue.front();
        outQueue.pop();
    }
    return result;
}

void TestClass::processResults()
{
    while(true)
    {
        const auto result = getResult();

        if(result.empty())
        {
            break;
        }

        std::cout << result << std::endl;

    }
}

static void sigIntHandler(std::shared_ptr<TestClass> t, int)
{
    t->shutDown();
}
static std::function<void(int)> handler;

int main()
{
    auto testClass = std::make_shared<TestClass>();
    handler = std::bind(sigIntHandler, testClass, std::placeholders::_1);
    std::signal(SIGINT, [](int n){ handler(n);});
    return 0;
}

我使用 gcc 5.2 使用 -std=c++14 标志编译了这个。在我的 CentOS 7 机器上按 Ctrl-C 时,我收到以下错误,

terminate called after throwing an instance of 'std::system_error'
  what():  Invalid argument
Aborted (core dumped)

请帮助我了解发生了什么。

标签: c++c++11signalssignal-handling

解决方案


SIGINT在您的平台上,当真正的信号到来时会调用此信号处理程序。可以在此信号处理程序内部调用的函数列表相当有限,调用其他任何函数都会导致未定义的行为。


推荐阅读