我怎样才能确保只有一个线程会做某事?

发布于 2024-11-17 00:08:38 字数 548 浏览 5 评论 0原文

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

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

具体来说:

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。 :(

I have multiple threads which add items to a lock-free queue.
The items are then processed by another thread.

In the producer threads, I need to kick off the consumer thread, but only if it's not already running or kicked off.

Specifically:

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();
}

I'm using .Net 3.5, not 4.0. :(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

抽个烟儿 2024-11-24 00:08:38

最简单的方法是使用信号量。它将有队列大小的计数。

The easiest way is to use Semaphore. It will have a count of queue size.

执手闯天涯 2024-11-24 00:08:38

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

///<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();
}

此模式安全吗?
有更好的方法吗?
班级有更正确的名称吗?

I created the following class to do this:

///<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;
    }
}

I use it like this:

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();
}

Is this pattern safe?
Is there a better way to do this?
Is there a more correct name for the class?

享受孤独 2024-11-24 00:08:38

这对你有用吗?

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); 
} 

Does this work for you?

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); 
} 
昵称有卵用 2024-11-24 00:08:38

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

与其让生产者线程尝试协调消费者线程的启动和停止,不如在启动任何生产者之前启动消费者线程,并让它闲置。调度程序应该在需要时自动唤醒它。

Create a second Dispatcher for the consumer thread. Then, producer threads can use that dispatcher's BeginInvoke() method to send data to the consumer thread. The Dispatcher's queue takes the place of your pendingActions queue, and ensures that the consumer thread is only processing one work item at a time.

Rather than having the producer threads try to coordinate starting and stopping the consumer thread, just start the consumer thread before any producers have been started, and let it sit idle. The Dispatcher should automatically take care of waking it up when needed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文