通知另一个线程数据可用的最快方法是什么?纺纱的替代品?

时间:2013-04-25 08:24:08

标签: c++ multithreading

我的一个线程将数据写入循环缓冲区,另一个线程需要尽快处理此数据。我想写这么简单的spin。伪码!

    while (true) {
        while (!a[i]) {
            /* do nothing - just keep checking over and over */
        }
        // process b[i]
        i++;
        if (i >= MAX_LENGTH) {
            i = 0;
        }
    }

上面我使用a表示存储在b中的数据可供处理。 Probaly我也应该为这种“热”过程设置线程。当然这种旋转在CPU方面非常昂贵,但对我来说没问题,因为我的主要要求是延迟

问题是 - 我应该写出类似的内容,或者booststl允许以下内容:

  1. 易于使用。
  2. 在占用较少的CPU资源的同时,大致相同(甚至更好?)延迟
  3. 我认为我的模式非常普遍,某处应该有一些好的实现。

    upd 看来我的问题仍然太复杂了。让我们考虑一下这种情况,当我需要以任意顺序将一些项目写入数组时,另一个线程应该在项目可用时以正确的顺序读取它们,该怎么做?

    UPD2

    我正在添加测试程序来演示我想要实现的目标和方式。至少在我的机器上它恰好起作用。我正在使用rand向您显示我无法使用通用queue,我需要使用array-based结构:

    #include "stdafx.h"
    #include <string>
    #include <boost/thread.hpp>
    #include "windows.h" // for Sleep
    
    
    const int BUFFER_LENGTH = 10;
    int buffer[BUFFER_LENGTH];
    short flags[BUFFER_LENGTH];
    
    void ProcessorThread() {
        for (int i = 0; i < BUFFER_LENGTH; i++) {
            while (flags[i] == 0);
            printf("item %i received, value = %i\n", i, buffer[i]);
        }
    }
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        memset(flags, 0, sizeof(flags));
        boost::thread processor = boost::thread(&ProcessorThread);
        for (int i = 0; i < BUFFER_LENGTH * 10; i++) {
            int x = rand() % BUFFER_LENGTH;
            buffer[x] = x;
            flags[x] = 1;
            Sleep(100);
        }
        processor.join();
        return 0;
    }
    

    输出:

    item 0 received, value = 0
    item 1 received, value = 1
    item 2 received, value = 2
    item 3 received, value = 3
    item 4 received, value = 4
    item 5 received, value = 5
    item 6 received, value = 6
    item 7 received, value = 7
    item 8 received, value = 8
    item 9 received, value = 9
    

    我的计划是否有效?您如何重新设计它,可能使用boost / stl中的一些现有结构而不是数组?是否有可能在不影响延迟的情况下摆脱“旋转”?

5 个答案:

答案 0 :(得分:3)

如果消耗线程进入休眠状态,它需要几微秒才能唤醒。这是您无法避免的进程调度程序延迟,除非线程像您一样忙着旋转。该线程还需要是实时FIFO,以便它在准备运行时永远不会进入休眠状态但耗尽其时间量。

因此,没有其他方法可以匹配繁忙旋转的延迟。

(令人惊讶的是你正在使用Windows,如果你认真对待HFT,最好避免使用。)

答案 1 :(得分:2)

这是 Condition Variables 的目的。 std::condition_variable在C ++ 11标准库中定义。

对于您的目的来说最快的取决于您的问题;您可以从多个角度对其进行攻击,但CV(或衍生实现)是更好地理解主题并接近实现的良好起点。

答案 2 :(得分:0)

如果您的编译器支持C ++ 11库,请考虑使用它。或boost analog如果没有。在您的情况下尤其std::futurestd::promise

有一本关于线程和C ++ 11线程库的好书:

Anthony Williams. C++ Concurrency in Action (2012)

来自cppreference.com的示例:

#include <iostream>
#include <future>
#include <thread>

int main()
{
// future from a packaged_task
std::packaged_task<int()> task([](){ return 7; }); // wrap the function
std::future<int> f1 = task.get_future();  // get a future
std::thread(std::move(task)).detach(); // launch on a thread

// future from an async()
std::future<int> f2 = std::async(std::launch::async, [](){ return 8; });

// future from a promise
std::promise<int> p;
std::future<int> f3 = p.get_future();
std::thread( [](std::promise<int>& p){ p.set_value(9); }, 
             std::ref(p) ).detach();

std::cout << "Waiting..." << std::flush;
f1.wait();
f2.wait();
f3.wait();
std::cout << "Done!\nResults are: "
          << f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';

}

答案 3 :(得分:0)

如果你想要一个快速方法,那么只需简单地进行OS调用。包装它们的任何C ++库都会变慢。

e.g。在Windows上,您的使用者可以调用WaitForSingleObject(),并且您的数据生成线程可以使用SetEvent()唤醒使用者。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx

对于Unix,这里有一个类似的答案问题:Windows Event implementation in Linux using conditional variables?

答案 4 :(得分:0)

你真的需要线程吗?

单线程应用程序非常简单,消除了线程安全性和启动线程开销的所有问题。我研究了线程与非线程代码,以便将文本附加到日志文件中。非线程代码在每个性能指标中都更好。