Understanding common problems and their causes - C#. NET

Take a look at the examples in this section for help in troubleshooting common Task programming problems.

Task Dependency Deadlock
If two or more Tasks depend on each other to complete, none can move forward without the others, so a deadlock (the condition where the Tasks involved cannot progress) occurs.

The only way to avoid this problem is to ensure that your Tasks do not depend on one another. This requires careful attention when writing your Task bodies and thorough testing. You can also use the debugging features of Visual Studio 2010 to help detect deadlocks.

In the following example, two Tasks depend upon one another, and each requires the result of the other to generate its own result. When the program is run, both Tasks are started by the main application thread and deadlock. Because the main thread waits for the Tasks to finish, the whole program seizes up and never completes.

Local Variable Evaluation
Assume that you create a series of Tasks in a for loop and refer to the loop counter in your lambda expressions. All of the Tasks end up with the same value because of the way that the C# variable scoping rules are applied to lambda expressions.

The simplest way to fix this problem is to pass the loop counter in as a state object to the Task.

In the following example, five Tasks print out a message that references the counter of the loop that created them, and they all print the same value. Another five Tasks do the same thing, but get their values as state objects, and these get the expected values.

Excessive Spinning
Many programmers overestimate the performance impact of a Task waiting (either via Thread.Sleep() or by using a CancellationToken wait handle) and use spin waiting instead (through the Thread.SpinWait() method or by entering a code loop).

For anything other than exceptionally short waits, spin waiting and code loops will cripple the performance of your parallel program, because avoiding a wait also avoids freeing up a thread for execution.

Restrict your use of spin waiting and code loops to situations where you know that the condition that you are waiting for will take only a few CPU cycles. If you must avoid a full wait, use spin waiting in preference to code loops.

In the following example, one Task enters a code loop to await the cancellation of another Task. Another Task does the same thing but uses spin waiting. On the quad-core machine that this example burns roughly 30 percent of the available CPU, which is quite something for a program that does nothing at all. You may get different results if you have fewer cores.

All rights reserved © 2020 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

C#. NET Topics