4

在我之前的问题中,有人说在 C# 中使用信号量比使用监视器要昂贵。所以我问这个,如何用监视器替换这段代码中的信号量?

在function2(在单独的线程中)完成后,我需要function1返回它的值。我已经Semaphore.WaitOne用 aMonitor.Wait和a 替换了Semaphore.Releasea ,Monitor.PulseAll但是在导致程序挂起PulseAll之前被触发了。Wait知道如何避免这种竞争条件吗?

Semaphore semaphore = new Semaphore(0,1);
byte b;
public byte Function1()
{
    // new thread starting in Function2;

    semaphore.WaitOne();
    return b;
}

public void Function2()
{
    // do some thing
    b = 0;
    semaphore.Release();
}
4

2 回答 2

8

您可以使用 WaitHandle 而不是 Semaphore 来执行此操作。这将是最简单的替代方案,并且比 Semaphore 执行得更好:

ManualResetEvent manualResetEvent = new ManualResetEvent(false);
byte b;
public byte Function1()
{
    // new thread starting in Function2;

    manualResetEvent.WaitOne();
    return b;
}

public void Function2()
{
    // do some thing
    b = 0;
    manualResetEvent.Set();
}
于 2010-04-02T17:59:54.573 回答
2

如果您需要等待多个线程,@Reed 提供了一个优雅的解决方案。

您可能不想使用Monitor它。正如@Reed指出的那样,一个事件就足够了,并且会提供符合您的代码要求的最简洁和最易理解的解决方案。
在您的情况下,使用真正的操作系统同步原语的开销很可能无关紧要,使用 egMonitor只会以更高的复杂性为代价提供递减的回报。

话虽如此,这是一个使用Monitor和信令的实现。

您可以使用bool由锁保护的标志来指示您已完成并避免在这种情况下等待。(A)
如果您真的Function2()在注释指示的地方开始一个新线程并在两者lock()周围使用and ,则根本不需要该标志。(乙) WaitOne()Release()

A、使用标志:

class Program
{
    static object syncRoot = new object();
    //lock implies a membar, no need for volatile here.
    static bool finished = false;
    static byte b;

    public static byte Function1()
    {
        lock (syncRoot)
        {
            //Wait only if F2 has not finished yet.
            if (!finished)
            {
                Monitor.Wait(syncRoot);
            }
        }
        return b;
    }

    static public void Function2()
    {
        // do some thing
        b = 1;
        lock (syncRoot)
        {
            finished = true;
            Monitor.Pulse(syncRoot);
        }
    }

    static void Main(string[] args)
    {
        new Thread(Function2).Start();
        Console.WriteLine(Function1());
    }
}

B,从以下开始一个线程Function1

class Program
{

    static object syncRoot = new object();
    static byte b;

    public static byte Function1()
    {
        lock (syncRoot)
        {
            // new thread starting in Function2;
            new Thread(Function2).Start();
            Monitor.Wait(syncRoot);
        }
        return b;
    }

    static public void Function2()
    {
        // do some thing
        b = 1;
        //We need to take the lock here as well
        lock (syncRoot)
        {
            Monitor.Pulse(syncRoot);
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine(Function1());
    }
}
于 2010-04-02T18:57:34.987 回答