为啥我会在这个程序中“中止”? [复制]

Posted

技术标签:

【中文标题】为啥我会在这个程序中“中止”? [复制]【英文标题】:Why do I get "abort" on this program? [duplicate]为什么我会在这个程序中“中止”? [复制] 【发布时间】:2017-02-07 16:24:18 【问题描述】:

让我们谈谈下一个代码示例:

#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <deque>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;
std::deque<int> queue;



void Inserter()

    int count = 10;
    while (count >= 0)
    
        std::unique_lock<std::mutex> lock(mtx);
        queue.push_back(count);
        --count;
        lock.unlock();
    


void Consumer()

    int count = 10, got;

    while (count >= 0)
    
        std::unique_lock<std::mutex> lock(mtx);
        if (!queue.empty())
        
            got = queue.back();
            queue.pop_back();
            std::cout << "We got: " << got << std::endl;
            --count;
            lock.unlock();
        
        else
        
            lock.unlock();
        
    


int main()

    std::thread t1(Inserter);
    std::thread t2(Consumer);

    std::cin.get();
    return 0;

当我运行这个程序时,我得到“中止”,但我不应该这样做。 我在这里看到中止的唯一原因是当我离开锁定的锁而没有打开它时 - 但是没有任何理由让锁保持锁定,因为在每个循环之后我都会打开锁。

你看到的原因是什么?

【问题讨论】:

您是否尝试使用调试器单步执行您的代码? 获得“中止”并不是具体的描述。您是否在标准库中触发断言,是否导致访问冲突,...? 如果这是 Visual Studio,请在对话框出现时按 Debug,然后将调用堆栈向上移动到您的代码。 【参考方案1】:

您不会在主程序中调用std::thread::join。当t2 超出范围时,你调用它的析构函数,由于你还没有加入线程,它会导致中止。

顺便说一句,您无需致电lock.unlock()std::unique_lock 的全部意义在于它会在对象被破坏时自动执行此操作。 (在您从队列中获取值的地方声明 got 会更简洁。)

所以你的代码应该是这样的:

#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <deque>

std::mutex mtx;
std::deque<int> queue;

void Inserter()

    for (int count = 10; count >= 0; --count)
    
        std::unique_lock<std::mutex> lock(mtx);
        queue.push_back(count);
    


void Consumer()

    for (int count = 10; count >= 0; )
    
        std::unique_lock<std::mutex> lock(mtx);
        if (!queue.empty())
        
            const int got = queue.back();
            queue.pop_back();
            std::cout << "We got: " << got << std::endl;
            --count;
        
    


int main()

    std::thread t1(Inserter);
    std::thread t2(Consumer);

    t1.join();
    t2.join();

    std::cin.get();
    return 0;

调用join 的要求是因为一个常见的习惯用法是使Inserter 成为从std::thread 派生的类,并让Inserter 构造函数将合适的线程函数传递给std::thread 构造函数。如果类包含线程方法访问的成员变量,那么如果在对象被破坏后线程方法继续运行,那就不好了。该标准要求您通过调用join(在这种情况下线程方法已完成)或调用detach(在这种情况下,您有责任确保不访问已经消失的变量)来避免这种情况超出范围)。

【讨论】:

你说得对。现在可以了。但它有什么理由自毁呢? t2 线程在 main 完成之前完成了他的工作(我有 cin 可以阻止 main 超出范围) 我的段落解释了吗?【参考方案2】:

要解决您需要在两个线程上调用std::thread::join 的问题

int main()

       std::thread t1(Inserter);      
       std::thread t2(Consumer);
       t1.join();
       t2.join();

    return 0;

演示:here

【讨论】:

以上是关于为啥我会在这个程序中“中止”? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥从函数返回数组作为参数时,我会从函数中的数组中获取随机值? [复制]

为啥我会收到“不允许主机 '192.168.1.220' 连接到此 MySQL 服务器”? [复制]

std::cout 一个 null char* 指针如何中止程序? [复制]

为啥主机中止连接?

为啥我会收到 ValueError: could not convert string to float in Python? [复制]

为啥这个字符串反转 C 代码会导致分段错误? [复制]