c# - .NET并发问题: Can I yield a semaphore to another thread

标签 c# concurrency semaphore

我有多个线程共享一个信号量。线程 A 持有信号量(使用锁),线程 B 和 C 正在等待同一个信号量(也使用锁)。线程共享全局变量等。

C# 中是否有一种技术可用于关闭线程 B?我可以在 A 中设置一个标志并让线程 B 检查该标志并在它控制信号量后立即退出,但我不知道有任何技术允许线程 A 将信号量交给线程 B(并获取它当线程 B 退出时返回)而不会有线程 C 夺取控制权的风险。

有人对如何解决这个设计问题有任何建议吗?如果我处理不当,我可以根据需要重写程序。

[编辑] 一位评论者指出我使用了错误的术语。评论者是正确的——我使用的是临界区,但考虑到一切都在单个进程中运行,因此在此示例中,临界区在功能上等同于更通用的术语“信号量”。

[编辑] 有人要求提供更多详细信息,所以在这里。

可以有多个线程执行代码 A。永远只有一个线程执行代码 B。

代码A:

private static Thread workerThread = null;

lock (lockObject)
{
    ... do some work ...

    if (...condition...)
    {
        if (workerThread != null)
        {
            // Kill the worker thread and continue only after it is dead.
            quitWorkerThread = true;
            // Wait for the thread to die.
            while (workerThread.IsAlive)
            {
                Thread.Sleep(50);
            }
            workerThread = null;
            quitWorkerThread = false;
        } // if (workerThread != null)
    } // if (...condition...)

    ... do some more work ...

    if (...condition...)
    {
        if (workerThread == null)
        {
            // Start the worker thread.
            workerThread = new Thread(WorkerThread);
            workerThread.Start();
        } // if (workerThread == null)
    } // if (...condition...)

    ... do even more work ...

} // lock (lockObject)

代码 B:

private void WorkerThread()
{
    while (true)
    {
        if (quitWorkerThread)
        {
            return;
        }

        Thread.Sleep (2000);

        if (quitWorkerThread)
        {
            return;
        }

        lock(lockObject)
        {
            if (quitWorkerThread)
            {
                return;
            }
            ... do some work ...
        } // lock(lockObject)
    } // while (true)
} // WorkerThread

我怀疑我会使用 Aaron 解决方案的变体。我主要希望有更优雅的解决方案可用,但我怀疑就像这个项目的其他所有内容一样,都是蛮力和极端情况:-(。

最佳答案

我相当确定没有办法将控制权交给特定 线程,而这似乎正是您想要做的。您只能让步,期间 - 由 Windows 调度程序决定接下来运行哪个线程。

情况是你有三个线程,A、B 和 C。A 有锁,B 和 C 正在等待它,你想要一种方法来保证 B 下一个被执行。

显而易见的解决方案是使用多个锁和/或同步原语。您可以将 lock 的语义与 ManualResetEvent 结合起来。让线程 C 等待事件 进入临界区,而线程 B 只需等待临界区。在正常情况下,您会在释放锁之前发出事件信号,这让操作系统决定执行哪个线程。在特殊情况下,您根本不会发出事件信号,让线程 B 在 C 仍处于阻塞状态时执行。

一旦 B 完成,您就向事件发出信号让 C 完成。


一个(未经测试的)例子是:

// Main thread is Thread A
object myLock = new Object();
AutoResetEvent myEvent = new AutoResetEvent(false);
ManualResetEvent completedEvent = new ManualResetEvent(false);

ThreadPool.QueueUserWorkItem(s =>
{
    for (int i = 0; i < 10000; i++)
    {
        lock (myLock)
        {
            // Do some work
        }
    }
    completedEvent.Set();
});  // Thread B

ThreadPool.QueueUserWorkItem(s =>
{
    for (int i = 0; i < 10000; i++)
    {
        myEvent.WaitOne();
        lock (myLock)
        {
            // Do some work
        }
    }
});  // Thread C

// Main loop for thread A
while (true)
{
    lock (myLock)
    {
        // Do some work
        if (SomeSpecialCondition)
            break;
        else
            myEvent.Set();
    }
}

completedEvent.WaitOne(); // Wait for B to finish processing
if (SomeSpecialCondition) // If we terminated without signaling C...
    myEvent.Set();        // Now allow thread C to clean up

这实质上让线程 A 负责线程 C 何时开始执行。线程 A 和 B 将正常竞争,但由线程 A 向线程 C 发出事件信号。

关于c# - .NET并发问题: Can I yield a semaphore to another thread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2391190/

相关文章:

c# - 在这种情况下,String.Format 或 String.Replace 哪个更快?

c# - MonoMac 项目中的自定义选项卡

java并发数组列表访问

c - 为什么未命名的信号量在共享内存中使用时不会改变?

c - 使用来自多个文件的信号量 C-Windows

c# - MongoDB C# 驱动程序 - 将集合序列化为接口(interface)

oracle - 2 个用户同时运行一个存储过程 - 如果一次执行中的 DML 语句影响并行执行中的测试/条件会怎样?

java - 这个 Singleton 是线程安全的吗?

c++ - 如何将信号量与共享内存结合使用

c# - AutoMapper 实现(Post Static Api)