我尝试实现自己的调度队列,按照添加到队列的相同顺序调度任务。这样做的动机是由于缺少对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,它也会阻止。
简而言之,我需要一个尊重插入顺序的调度队列,而不会阻塞生成线程,因为它可以是主线程。是否有针对这些方法或您推荐的任何其他方法的修复方法?