如果我运行一个紧密的轮询循环,多核平台上的多线程程序不打印输出(std :: cout)

问题描述 投票:-1回答:1

正如OP所述,我有多个线程 - 其中两个是经常睡眠的紧密轮询循环(我需要轮询): - 每10秒后1秒睡眠。

程序有多个临时更新,可以打印:

std::cout << "progress report text" << std::endl;

民意调查的线程,几乎看起来像:

void PollHardwareFunction ()
{
    lastTimeSlept = std::chrono::HighResClock::now();
    while (!stopSignal)
    {
        poll_hardware();
        // Process the data received from hardware

        if (std::chrono::HighResClock::now() - lastTimeSlept > std::chrono::seconds(10))
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            auto lastTimeSlept = std::chrono::HighResClock::now();
        }
    }
}

其他线程非常正常,几乎没有逻辑步骤,并在每个步骤后打印状态。

void LongRunningFunction ()
{
    int dataCounter = 0;
    while (wait_for_data_from_hardware_in_concurrent_queue)
    {
        std::cout << "Data received: " << dataCounter++ << std::endl;

        // Process the data received from hardware
        std::cout << "STEP1 done." << std::endl;            
        std::cout << "STEP2 done." << std::endl;            
        std::cout << "STEP3 done." << std::endl;        
    }
}

这将按预期打印所有消息,但仅在10秒后批量打印。在这10秒内让它看起来没有响应/卡住。

程序在以下环境中运行:使用GCC 6.2编译,在RHEL 7上运行,这是一个8核CPU。

我注意到程序仅在旋转线程进入休眠/空闲状态时才在控制台上打印。一旦忙线程进入休眠状态,所有打印件一起出现在我的输出控制台上。要添加它,从硬件接收的数据是常规的 -​​ 比如每100毫秒。

有多个CPU内核可用,为什么程序保持无响应状态,直到旋转线程停止/暂停?

c++ multithreading
1个回答
1
投票

从你的评论:

我的程序结构更好 - 它使用原子变量和我实现的一些无锁数据结构。

poll_hardware是硬件供应商的API中的一个函数,它读取硬件缓冲区并将数据推送到并发队列。

这听起来很可疑。您是编写自己的数据结构还是使用现有数据结构?无论如何,请发布队列的代码。如果队列是由供应商提供的,请发布API。

我的观点是要了解什么会导致程序输出保持(感觉)卡在std :: cout <<运算符与std :: endl执行(完成执行)?

你没有从PollHardwareFunction()调用cout,所以问题必须来自wait_for_data_from_hardware_in_concurrent_queue阻止,当它不应该。 (如果你想确定,请将cout切换到cerr以避免缓冲写入。)

我要检查的第一件事是,如果poll_hardware()一发布,就会通过重新锁定来控制锁定。你可能已经创造了有效的自旋锁。这就是用户Snps建议在评论中睡眠1ms的原因。 1产量不够。我知道你的数据是时间关键的,但你说100毫秒,所以理论上你可以在50毫秒内进行轮询并且没问题。几毫秒应该完全可以用于调试目的。

锁定主导可以由读取器/写入器锁定引起并通过读取器/写入器锁定来解决。读/写锁需要根据具体情况进行定制设计。 (读取和写入的线程数是多少?读取与写入的频率是多少?)

我要检查的第二件事是您对无锁数据结构中的顺序编程和内存缓存的假设。负载和存储可以作为优化延迟,重新排列,缓冲等。每个人都是你的“朋友” - 编译器将执行此操作,然后操作系统将执行此操作,CPU将轮流执行,然后硬件也会执行此操作。

为了防止这种情况,你必须使用内存屏障(也就是内存栅栏)来阻止你的任何朋友优化内存访问。仅供参考,互斥体在其实施中使用内存屏障。查看这是否可以解决您的问题的一种快速方法是使您的共享变量不稳定。但是,不要相信不稳定。它只会阻止编译器重新排序命令,不一定是操作系统或CPU(当然,取决于编译器)。

了解一些其他原子变量会很好,因为那里可能存在逻辑错误。

最后,在这里你使用auto定义一个范围变量lastTimeSlept,阴影“实际”lastTimeSlept

if (std::chrono::HighResClock::now() - lastTimeSlept > std::chrono::seconds(10))
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    auto lastTimeSlept = std::chrono::HighResClock::now();
}

哎呀!不过,我认为这不会导致你的问题。

© www.soinside.com 2019 - 2024. All rights reserved.