具有执行顺序的非阻塞和重入调度队列

时间:2017-02-06 17:29:08

标签: multithreading c++-cx task-queue

我尝试实现自己的调度队列,按照添加到队列的相同顺序调度任务。这样做的动机是由于缺少对Windows运行时组件的调度队列的C ++ / CX支持。 This是我一直在考虑的文档。我知道这与Producer-consumer problem有关,但我还没有设法使用C ++ / CX来解决它。鉴于此,我已经尝试了几种解决此问题的方法。

根据我在网上找到的几个例子和文档,我尝试使用信号量来解决这个问题。为此,我创建了一个DispatchQueue类,它包含几个属性:

namespace Threading
{
    ref class DispatchQueue
    {

    private:
        typedef IMap<String^, DispatchQueue^> MapType;
        typedef std::function<void()> TaskType;
        typedef std::queue<TaskType> QueueType;

    internal:

        static DispatchQueue^ Get();

        void Add(TaskType task);

    private:
        TaskType DequeueTask();
        void Runner();

        QueueType & GetQueue();
        const QueueType & GetQueue() const;

    private:
        QueueType _queue;
        std::mutex _queue_mux;
        std::mutex _add_mux;
        HANDLE _emptySemaphore;
        HANDLE _fullSemaphore;
    };
}

(注意:我没有发布实际的代码,因为这个类已被大量迭代,现在它非常混乱。如果您需要其他详细信息,请告诉我。)

这里是如何初始化信号量的;至少那是构造函数的相关部分:

Threading::DispatchQueue::DispatchQueue(String^ identifier)
    : _queue(),_emptySemaphore(CreateSemaphore(NULL, 1, 1, NULL)), _fullSemaphore(CreateSemaphore(NULL, 0, 1, NULL))
{
}

这是我的制作人:

void Threading::DispatchQueue::Add(TaskType task)
{
    // Prevent different threads from entering this method
    // Disregard the mutex being static
    static std::mutex mux;
    std::lock_guard<std::mutex> lock(mux);

    WaitForSingleObject(_emptySemaphore, INFINITE);
    {
        // Prevent concorrent access to the queue
        std::lock_guard<std::mutex> lock(_queue_mux);
        GetQueue().push(task);
    }
    ReleaseSemaphore(_fullSemaphore, 1, NULL);
}

这是消费者:

void Threading::DispatchQueue::Runner()
{
    while (true)
    {
        WaitForSingleObject(_fullSemaphore, INFINITE);

        TaskType task = DequeueTask();

        task();

        if (!ReleaseSemaphore(
            _emptySemaphore,
            1,
            NULL)) {
        }
    }
}

我已尝试在发布信号量后调度任务(task();,但它也没有工作。同样值得注意的是Runner(消费者)是在初始化点启动的:

    create_task([dispatchQueue]() {

        dispatchQueue->Runner();
    });

这种方法的问题在于调用task();也可能产生新任务(TaskType),但这似乎不是可重入的。因此,实现块。发生锁定是因为任务在没有释放信号量的情况下进入Add方法。

我已经迭代并尝试过这个制作人:

void Threading::DispatchQueue::Add(TaskType task)
{
    create_task([this, task]()
    {
        WaitForSingleObject(_emptySemaphore, INFINITE);
        {
            std::lock_guard<std::mutex> lock(_queue_mux);
            GetQueue().push(task);
        }
        ReleaseSemaphore(_fullSemaphore, 1, NULL);

    }).wait();   // Notice we're waiting
}

wait()背后的动机是保证任务以正确的顺序插入队列。这确实有效,但如果从UI线程调用此方法,则会崩溃。这不是一个选择。此外,不等待不是一种选择,因为再次,任务不会以正确的顺序发送。

我也试过了this,它也会阻止。

简而言之,我需要一个尊重插入顺序的调度队列,而不会阻塞生成线程,因为它可以是主线程。是否有针对这些方法或您推荐的任何其他方法的修复方法?

0 个答案:

没有答案