如何实现以下线程同步?

时间:2017-10-02 21:19:42

标签: c# multithreading synchronization locking mutex

我有一个名为Wait()的方法,它执行一个长时间运行的工作。它是同步的(它会阻止线程直到操作完成)

我想编写一个Foo()方法来实现以下逻辑:

  

调用Foo()方法的第一个线程应该调用Wait()   如果另一个线程在Wait()方法调用一次后调用Foo()(并且还没有返回),它应该等待/阻塞,直到初始Wait()调用完成。

我写了以下代码,但我不确定它是否是线程安全的。也许有更好的方法。 我还尝试使用Monitor.Pulse() / Monitor.Wait()来实现逻辑,但是没有成功。

void Foo()
{
    if (Monitor.TryEnter(mylock))
    {
        try
        {
            Wait();
        }
        finally
        {
            Monitor.Exit(mylock);
        }
    }
    else
    {
        lock(mylock) {}
    }
}

2 个答案:

答案 0 :(得分:0)

使用共享整数来指示生成和共享布尔值,以指示线程是否在Wait中被阻止。

布尔值跟踪另一个线程是否要调用wait。如果它是true,那么我们只需等待(释放监视器),直到其他线程从等待返回。我们知道这是因为它增加了共享整数。如果它是false,那么我们必须调用wait函数。为了让其他线程(如果有的话)知道等待返回,我们递增共享整数并对它们进行脉冲。

这是逻辑:

  1. 锁定显示器。
  2. 检查共享布尔值,如果它是true,请转到步骤12。
  3. 将布尔值设置为true
  4. 解锁显示器。
  5. 调用特殊的Wait函数。
  6. 锁定显示器。
  7. 递增共享整数
  8. 将共享布尔值设置为false
  9. 在显示器上拨打PulseAll
  10. 解锁显示器。
  11. 返回。
  12. 将共享整数复制为专用整数。
  13. 在显示器上拨打Wait
  14. 如果共享整数等于私有整数,请转到步骤2.
  15. 解锁显示器。
  16. 返回。

答案 1 :(得分:0)

这可以通过信号量轻松完成,你只需要等待0的超时,如果它没有等待你去其他地方,你等到它发出信号。

SemaphoreSlim _semaphore = ...

void Foo()
{

    try
    {
        if (_semaphore.Wait(0))
        {
            Wait();
        }
        else
        {
            _semaphore.Wait()
        }
    }
    finally
    {
        _semaphore.Release();
    }
}