简体   繁体   中英

Why this lock statement does not work

So I have this fairly simple code. Take a look.

var monitor = new object();

var result = 0;

Task.Factory.StartNew(() =>
{
    var childTaskFactory = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously);
    for (int i = 0; i < 5; i++)
    {
        childTaskFactory
            .StartNew<int>(() => CreateRequest()) // this methods just return the integer value 10
            .ContinueWith(task => { lock (monitor) { result += task.Result; } });
    }
}).Wait();

Basically I am instantiating a new object to be used for acquiring lock. then I am creating an int variable which is set to 0. After that I am creating one parent Task which will contain 5 child Task s and all of those child task call a method called CreateRequest which just return a number 10 (don't mind the name of the method). Each child Task has a continuation which acquires lock on the monitor and just adds number 10 returned by the CreateRequest method to the result variable. At the end of the program I expect the variable result to contain the value 50. But it does not. I mean sometimes it does but some times it is set to 20, 30 or 40. Apparently either I am misunderstanding how to use lock statement or there is something wrong with the implementation. Most probably I have some mistake in a code. This code is inside the static Main method of the Program class.

Because your main task completes when all of the other tasks have started. It doesn't wait for them all to finish . So sometimes you're capturing the value of result before all of the child tasks have run.

As a test, put a Thread.Sleep(1000) after the Wait() , and you'll see that result is updated as expected. But don't use that for production code. Rather, write code that waits for all of the child tasks to finish.

If I understand the code correctly, it's not actually waiting for all 5 tasks to complete. Instead, it's waiting for all 5 tasks to be started, during which time apparently one or more of the tasks may complete, giving you 10, 20, 30, or 40 rather than 50.

Here's an example of waiting on more than one task to complete. You'll want the WaitAll version, not the WaitAny .

You can also examine what is happening by adding the child tasks into a List and then adding a breakpoint at the end. If you then examine the objects in the Locals window you will see that the status of some tasks will still be Running.

Note that adding the tasks into a List may affect the execution and cause the result to equal 50 more often.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM