4

I have this code which creates a deadlock :

void Main()
{
    ClassTest test = new ClassTest();
    lock(test)
    {

        Task t1 = new Task(() => test.DoWorkUsingThisLock(1));
        t1.Start();
        t1.Wait();

    }
}

public class ClassTest
{
    public void DoWorkUsingThisLock(int i)
    {
        Console.WriteLine("Before " + i);
        Console.WriteLine ("Current Thread ID is = "+Thread.CurrentThread.ManagedThreadId);
        lock(this)
        {
            Console.WriteLine("Work " + i);
            Thread.Sleep(1000);
        }
        Console.WriteLine("Done " + i);
    }
}

Result :

Before 1
(and deadlock....)

I know that this is a bad practice to lock over instances beyond code's control or , this. But it's just for this question.

I can understand why a deadlock is created here.

The main thread acquires the lock(test) in main and then a new thread starts to invoke DoWorkUsingThisLock - there it tries to acquire a lock over the same instance variable and it's stuck ( because of t1.Wait() at main)

OK

But I've seen this answer here which also creates deadlock.

void Main()
{
    ClassTest test = new ClassTest();
    lock(test)
    {
        Parallel.Invoke (
            () => test.DoWorkUsingThisLock(1),
            () => test.DoWorkUsingThisLock(2)
        );
    }
}

public class ClassTest
{
    public void DoWorkUsingThisLock(int i)
    {
        Console.WriteLine("Before ClassTest.DoWorkUsingThisLock " + i);
        lock(this)
        {
            Console.WriteLine("ClassTest.DoWorkUsingThisLock " + i);
            Thread.Sleep(1000);
        }
        Console.WriteLine("ClassTest.DoWorkUsingThisLock Done " + i);
    }
}

The result is :

Before ClassTest.DoWorkUsingThisLock 1
Before ClassTest.DoWorkUsingThisLock 2
ClassTest.DoWorkUsingThisLock 1 // <---- how ?
ClassTest.DoWorkUsingThisLock Done 1

Question:

How come it DID acquire the lock for the first invocation (DoWorkUsingThisLock(1))? The lock at main is still blocked due to Parallel.Invoke which DOES block ! I don't understand how the thread has succeeded to enter the lock(this) section.

4

1 回答 1

4

The Parallel class uses the current thread to do a part of the work. This is a nice performance optimization but it is observable in the case of thread-specific state.

The TPL has this kind of "inline execution" in many places and it causes a lot of trouble in different ways. Many programs are not made to deal with reentrancy.

于 2015-08-13T12:28:14.560 回答