【问题标题】:TaskScheduler to always run on the same threadTaskScheduler 总是在同一个线程上运行
【发布时间】:2016-12-05 22:50:33
【问题描述】:

我有一些使用 ReaderWriterLockSlim 的代码。当构造某个对象时,我会在其上获取写锁,并在稍后处理该对象时释放它。但是,由于这些调用来自哪里,我不能保证它们会在同一个线程上,这是 ReaderWriterLockSlim 的要求。

我相信一个合理的解决方案是在专用线程上运行对象的构造和处置,并让调用代码等待该任务完成(但保持线程处于活动状态)。看起来很乱,但如果不大规模重组我们的代码,我想不出另一种方法。

是否存在允许我在同一个线程上运行两个任务的现有 TaskScheduler 子类?

我当然愿意接受另一种这样做的范例。

【问题讨论】:

  • 您使用的是 WPF 还是 Windows.Forms?还是 ASP.Net?这将极大地影响答案:)
  • 有趣 - 包含 ReaderWriterLockSlim 的底层库被多个应用程序使用;一些在 Windows 窗体中,一些在 WPF 中;虽然有问题的情况是在我们的 WPF 应用程序中使用它时。
  • 在 WPF 中创建的普通任务都应该在同一个线程上运行,即 Dispatcher 线程。但对于“长时间运行”的任务以及在线程池上显式创建的任务,情况并非如此。 msdn.microsoft.com/magazine/gg598924.aspx
  • Here 是一篇博客文章,介绍了如何构造为async 代码设计的读/写锁。

标签: c# .net multithreading readwritelock


【解决方案1】:

我遇到了类似的问题,所以我希望我的解决方案也能帮助到你。

基本上,问题在于 ReaderWriterLockSlim 具有线程亲和性,这意味着获得锁的线程是唯一可以释放它的线程。

解决方案是再创建一个专用线程,但与您的建议相反,该线程将专用于获取和释放锁。

我猜你的代码看起来像这样:

public class ClassUsingReaderWriterLockSlim
{
    private ReaderWriterLockSlim rwsLock;

    public void MethodThatAcquiresLock()
    {
        rwsLock.EnterWriteLock();
    }

    public void MethodThatReleasesLock()
    {
        rwsLock.ExitWriteLock();
    }
}

解决您的问题的代码如下所示:

public class ClassUsingReaderWriterLockSlim
{
    private ReaderWriterLockSlim rwsLock;
    Thread dedicatedThreadForReaderWriterLockSlim;
    Queue<string> commandsForDedicatedThread;

    public ClassUsingReaderWriterLockSlim()
    {
        commandsForDedicatedThread = new Queue<string>();
        dedicatedThreadForReaderWriterLockSlim = new Thread(ThreadFunction);
        dedicatedThreadForReaderWriterLockSlim.Start();
    }

    private void ThreadFunction(object obj)
    {
        while (!terminatingCondition)
        {
            // Wait until something is in queue...

            if (commandsForDedicatedThread.Count > 0)
            {
                switch (commandsForDedicatedThread.Dequeue())
                {
                    case "ENTER LOCK":
                        rwsLock.EnterWriteLock();
                    case "EXIT LOCK":
                        rwsLock.EnterWriteLock();
                    default:
                    // Do nothing...
                }
            }
        }
    }

    public void MethodThatAcquiresLock()
    {
        commandsForDedicatedThread.Enqueue("ENTER LOCK");
    }

    public void MethodThatReleasesLock()
    {
        commandsForDedicatedThread.Enqueue("EXIT LOCK");
    }
}

好吧,对于您的生产代码,您可能会有所不同,但基本想法是有专用线程来执行锁定和解锁,这样从哪个线程调用开始并不重要应该锁定和解锁代码/资源的方法...

希望对你有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2012-07-21
    • 2022-01-08
    • 2019-04-26
    • 2019-08-16
    • 2016-03-29
    • 2016-02-10
    相关资源
    最近更新 更多