C++11 带有线程安全队列的事件循环

6
我想创建一个事件循环类,它可以在自己的线程上运行,支持添加std::functions作为任务并执行它们。为此,我使用了这里的SafeQueue: https://dev59.com/tWUp5IYBdhLWcg3wbnMS#16075550
class EventLoop
{
public:
typedef std::function<void()> Task;

EventLoop(){ stop=false; }

void add_task(Task t) { queue.enqueue(t); }

void start();

void stop() { stop = true; }

private:
    SafeQueue<Task> queue;
    bool stop;
};

void EventLoop::start()
{
    while (!stop) {
        Task t = queue.dequeue(); // Blocking call
        if (!stop) {
            t();
        }
    }    

    cout << "Exit Loop";
}

然后,您可以像这样使用它:
EventLoop loop;
std::thread t(&EventLoop::start, &loop);

loop.add_task(myTask);
// do smth else

loop.stop();
t.join();

我的问题是:如何优雅地停止线程? 在这种情况下,由于阻塞队列的调用,无法使用停止来退出循环。


作为一条注释,我认为也许有一个“空闲/重复”列表会很有帮助。 - Mooing Duck
是否有类似于 bool SafeQueue<T>::try_dequeue(Task& out, std::chrono::milliseconds timeout); 的函数或者类? - Mooing Duck
如果可能的话,我会考虑使用TBB的并发队列容器来实现高性能,而不是依赖于简单的阻塞互斥锁。 - sjdowling
@sjdowling,谢谢,TBB看起来很有趣。 - yandreiy
2个回答

5
排队一个“毒丸”停止任务。这将解除队列等待并直接请求线程清理并退出,或允许使用者线程检查“停止”布尔值。
这是假设您需要在应用程序终止之前停止线程/任务。如果可以避免停止线程/任务,我通常会尝试不这样做。

1
一种替代方法:只需排队一个抛出异常的任务。对您的代码进行一些更改:

class EventLoop {

// ...

    class stopexception {};

// ...


    void stop()
    {
          add_task(
               // Boring function that throws a stopexception
          );
    }
};

void EventLoop::start()
{
    try {
        while (1)
        {
            Task t = queue.dequeue(); // Blocking call
            t();
        }
    } catch (const stopexception &e)
    {
        cout << "Exit Loop";
    }
}

对于那些对异常过敏的人来说,不使用异常的替代方案是将Task重新定义为一个函数,该函数仅以EventLoop引用作为其唯一参数,并且stop()会排队一个任务来设置打破主循环的标志。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接