我的一个线程将数据写入循环缓冲区,另一个线程需要尽快处理此数据。我想写这么简单的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方面非常昂贵,但对我来说没问题,因为我的主要要求是延迟。
问题是 - 我应该写出类似的内容,或者boost
或stl
允许以下内容:
我认为我的模式非常普遍,某处应该有一些好的实现。
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中的一些现有结构而不是数组?是否有可能在不影响延迟的情况下摆脱“旋转”?
答案 0 :(得分:3)
如果消耗线程进入休眠状态,它需要几微秒才能唤醒。这是您无法避免的进程调度程序延迟,除非线程像您一样忙着旋转。该线程还需要是实时FIFO,以便它在准备运行时永远不会进入休眠状态但耗尽其时间量。
因此,没有其他方法可以匹配繁忙旋转的延迟。
(令人惊讶的是你正在使用Windows,如果你认真对待HFT,最好避免使用。)
答案 1 :(得分:2)
这是 Condition Variables 的目的。 std::condition_variable
在C ++ 11标准库中定义。
对于您的目的来说最快的取决于您的问题;您可以从多个角度对其进行攻击,但CV(或衍生实现)是更好地理解主题并接近实现的良好起点。
答案 2 :(得分:0)
如果您的编译器支持C ++ 11库,请考虑使用它。或boost analog如果没有。在您的情况下尤其std::future
与std::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)
你真的需要线程吗?
单线程应用程序非常简单,消除了线程安全性和启动线程开销的所有问题。我研究了线程与非线程代码,以便将文本附加到日志文件中。非线程代码在每个性能指标中都更好。