2

I have written a DirectSoundWrapper but I just can access the interfaces through MTA Threads. So I created a Thread that is working in background and executes actions in a queue. I've done something like this:

private void MTAQueue()
{
    lock (queueLockObj)
    {
        do
        {
            if (marshalThreadItems.Count > 0)
            {
                MarshalThreadItem item;
                item = marshalThreadItems.Dequeue();
                item.Action();
            }
            else
            {
                Monitor.Wait(queueLockObj);
            }
        } while (!disposing);
    }
}

And I Execute an Action like this:

private void ExecuteMTAAction(Action action)
{
    if (IsMTAThread)
        action();
    else
    {
        lock (queueLockObj)
        {
            MarshalThreadItem item = new MarshalThreadItem();
            item.Action = action;
            marshalThreadItems.Enqueue(item);

            Monitor.Pulse(queueLockObj);
        }
    }
}

But now I wanted to wait for the finishing the action is called. So I wanted to use a ManuelResetEvent:

private void ExecuteMTAAction(Action action)
{
    if (IsMTAThread)
        action();
    else
    {
        lock (queueLockObj)
        {
            MarshalThreadItem item = new MarshalThreadItem();
            item.Action = action;
            item.waitHandle = new ManualResetEvent(false); //setup
            marshalThreadItems.Enqueue(item);

            Monitor.Pulse(queueLockObj); //here the pulse does not pulse my backgrond thread anymore
            item.waitHandle.WaitOne(); //waiting
        }
    }
}

And my background thread i just edit like this:

item.Action();
item.waitHandle.Set();

The problem is that the background thread does not get pulsed anymore and just keeps waiting (Monitor.Wait(queueLockObj)) and my mainthread that calls the action waits on the manuelresetevent...?

Why?

4

1 回答 1

0

您的代码中的问题是,在Monitor.Wait(queueLockObj)将退出并且线程可以处理项目之前,另一个线程(ExecuteMTAAction方法)必须调用Monitor.Exit(queueLockObj),但是调用item.waitHandle.WaitOne()阻止了此调用-并且您有死锁。所以 - 你必须先Monitor.Exit(queueLockObj)打电话item.waitHandle.WaitOne()。这段代码可以正常工作:

private void ExecuteMTAAction(Action action)
{
    if (IsMTAThread)
        action();
    else
    {
        lock (queueLockObj)
        {
            MarshalThreadItem item = new MarshalThreadItem();
            item.Action = action;
            item.waitHandle = new ManualResetEvent(false); //setup
            marshalThreadItems.Enqueue(item);

            Monitor.Pulse(queueLockObj);
        }
            item.waitHandle.WaitOne(); //waiting           
    }
}
于 2013-08-05T21:27:19.717 回答