使整个方法线程安全的最简单方法是什么?

Igb*_*man 9 .net multithreading reentrancy

关于多线程编程似乎有很多东西需要学习,而且它有点令人生畏.

对于我目前的需求,我只想防止在完成之前从另一个线程再次调用的方法,我的问题是:

这是一种使方法线程安全的充分(安全)方法吗?

class Foo
{
    bool doingWork;
    void DoWork()
    {
        if (doingWork)  // <- sophistocated thread-safety
            return;     // <-

        doingWork = true;

        try
        {
            [do work here]
        }
        finally
        {
            doingWork = false;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果这还不够,最简单的方法是什么?


编辑:有关场景的更多信息:

  • Foo只有一个例子

  • 将在System.Timers.Timer的Elapsed事件上从ThreadPool线程调用Foo.DoWork().

  • 通常Foo.DoWork()会在下次调用之前完成eons,但是我想编码它运行时间很长的机会,并在完成之前再次调用.


(我也不够聪明,不能确定这个问题是否可以被标记为与语言无关,所以我没有.开明的读者,如果适用,请随意这样做.)

And*_*bel 8

您的代码不是线程安全的.您应该使用lock关键字.

在您当前的代码中:

  if (doingWork)
        return;

  // A thread having entered the function was suspended here by the scheduler.

  doingWork = true;
Run Code Online (Sandbox Code Playgroud)

当下一个线程通过时,它也将进入该功能.

这就是lock应该使用构造的原因.它基本上与您的代码相同,但没有线程在中间被中断的风险:

class Foo
{
    object lockObject = new object;
    void DoWork()
    {
        lock(lockObject)
        {
            [do work here]
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此代码的语义与原始语义略有不同.此代码将导致第二个线程进入等待然后执行工作.您的原始代码使第二个线程中止.为了更接近原始代码,lock不能使用C#语句.Monitor必须直接使用底层构造:

class Foo
{
    object lockObject = new object;
    void DoWork()
    {
        if(Monitor.TryEnter(lockObject))
        {
            try
            {
                [do work here]
            }
            finally
            {
                Monitor.Exit(lockObject);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)