9

我的一个线程将数据写入循环缓冲区,另一个线程需要尽快处理这些数据。本来想写这么简单的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可用于处理。可能我还应该为这种“热”进程设置线程亲和力。当然,这种旋转在 CPU 方面非常昂贵,但对我来说没关系,因为我的主要要求是延迟

问题是 - 我真的应该写这样的东西boost还是stl允许这样的东西:

  1. 更容易使用。
  2. 具有大致相同(甚至更好?)的延迟同时占用更少的 CPU 资源?

我认为我的模式非常普遍,应该在某个地方有一些好的实现。

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

更新2

我正在添加测试程序来演示我想要实现什么以及如何实现。至少在我的机器上它恰好可以工作。我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 中的一些现有结构而不是数组?是否可以在不影响延迟的情况下摆脱“旋转”?

4

5 回答 5

3

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

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

(令人惊讶的是,您使用的是 Windows,如果您对 HFT 很认真,最好避免使用它)。

于 2013-04-25T20:55:52.803 回答
2

这就是条件变量的设计目的。std::condition_variable在 C++11 标准库中定义。

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

于 2013-04-25T12:39:22.727 回答
1

如果您的编译器支持,请考虑使用 C++11 库。如果没有,或者提升模拟。在你的情况下,尤其std::futurestd::promise.

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

安东尼威廉姆斯。C++ 并发实践 (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';

}

于 2013-04-25T11:56:33.717 回答
0

如果您想要一种快速的方法,那么只需进行操作系统调用即可。任何包装它们的 C++ 库都会变慢。

例如,在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?

于 2013-04-25T13:12:46.647 回答
0

你真的需要线程吗?

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

于 2013-04-25T21:17:12.563 回答