繁体   English   中英

我如何确保只有一个线程可以执行某些操作?

[英]How can I make sure that exactly one thread will do something?

我有多个线程将项添加到无锁队列。
然后由另一个线程处理这些项目。

在生产者线程中,我需要启动消费者线程, 但前提是它尚未运行或启动

特别:

public void BeginInvoke(Action method)
{
    //This runs on multiple background threads
    pendingActions.Enqueue(method);
    if (ProcessQueue hasn't been posted)
        uiContext.Post(ProcessQueue, null);
}
private void ProcessQueue(object unused)
{
    //This runs on the UI thread.
    Action current;
    while (pendingActions.TryDequeue(out current))
        current();
}

我使用的是.Net 3.5,而不是4.0。 :(

我创建了以下类来执行此操作:

///<summary>Ensures that a block of code is only executed once at a time.</summary>
class Valve
{
    int isEntered;  //0 means false; 1 true

    ///<summary>Tries to enter the valve.</summary>
    ///<returns>True if no other thread is in the valve; false if the valve has already been entered.</returns>
    public bool TryEnter()
    {
        if (Interlocked.CompareExchange(ref isEntered, 1, 0) == 0)
            return true;
        return false;
    }

    ///<summary>Allows the valve to be entered again.</summary>
    public void Exit()
    {
        Debug.Assert(isEntered == 1);
        isEntered = 0;
    }
}

我这样使用它:

readonly Valve valve = new Valve();
public void BeginInvoke(Action method)
{
    pendingActions.Enqueue(method);
    if (valve.TryEnter())
        uiContext.Post(ProcessQueue, null);
}
private void ProcessQueue(object unused)
{
    //This runs on the UI thread.
    Action current;
    while (pendingActions.TryDequeue(out current))
        current();
    valve.Exit();
}

这种模式安全吗?
有一个更好的方法吗?
这个班的名字有更正确的名字吗?

最简单的方法是使用Semaphore 它将具有队列大小的计数。

这对你有用吗?

volatile int running;  //not a boolean to allow ProcessQueue to be reentrant.

private void ProcessQueue(object unused)
{
    do
    {
        ++running;
        Action current;
        while (pendingActions.TryDequeue(out current))
            current();

        --running;
    }
    while (pendingActions.Count != 0);
} 

public void BeginInvoke(Action method) 
{     
    pendingActions.Enqueue(method);
    if (running != 0)
        uiContext.Post(ProcessQueue, null); 
} 

为使用者线程创建第二个Dispatcher 然后,生产者线程可以使用该调度程序的BeginInvoke()方法将数据发送到使用者线程。 Dispatcher的队列取代pendingActions队列,并确保使用者线程一次只处理一个工作项。

而不是让生产者线程尝试协调启动和停止使用者线程,只需在任何生成器启动之前启动使用者线程,并让它闲置。 Dispatcher应该在需要时自动将其唤醒。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM