Thread conflicts in. NET Programming

Source: Internet
Author: User

1. What is thread conflict?

A thread conflict occurs when two or more threads operate on the same shared resource at the same time.

A typical example is to use a global variable as a counter, and then open N threads to complete a task. After each thread completes a task, it will add a counter until 100 tasks are completed. If you do not consider thread conflicts and use code similar to the following, the task may be overfulfilled. The more threads there are, the more likely the number of completed tasks exceeds 100.

The pseudocode is as follows:

Int count = 0; // Global Counter

Void ThreadMethod () // method that runs in each thread

{

While (true)

{

If (count> = 100) // if the task metrics are reached

Break; // interrupt thread execution

DoSomething (); // completes a task

Count ++;

}

}

// Omitting Code such as thread creation.

Specifically, I will not go into details about the reason why the task will be overfulfilled. This example will never overfulfill the task in a single-threaded environment.

Of course, in this example, placing count ++ in the if statement may reduce the probability of some accidents, but that is not absolute, in other words, such a program cannot overfulfill the task.

In fact, from the definition of thread conflicts, it is not difficult to find that there are two necessary conditions for thread conflicts: multithreading and sharing resources. If one of the two conditions is invalid, thread conflict cannot occur.

Therefore, there is no thread conflict in a single-threaded environment. However, it is a pity that our software has evolved into the multi-process and multi-thread era, and the single-threaded program almost does not exist. Whether it is WinForm or WebForm, the running environment is multi-threaded, whether you have enabled a thread explicitly or not.

Since multithreading is inevitable, to avoid thread conflicts, we can only open the knife from sharing resources.

Ii. Thread-Safe Resources

If you often see MSDN or VS help. NET class library reference, it is not difficult to find that almost all types have such a statement: "Any public static (Shared in Visual Basic) Members of this type are thread-safe. However, it is not guaranteed that all instance members are thread-safe ." So what does thread security mean?

In fact, thread security is very simple. It means that a function (method, attribute, field, or other) is used by different threads at the same time without causing any thread conflicts. This is thread-safe.

Next, let's talk about what kind of resources are thread-safe.

The term resource is used because thread conflicts not only occur on shared variables, but both threads simultaneously read and write the same file, both programs use the same port to communicate with the same address at the same time, which may cause thread conflicts. It's just that the operating system coordinates these conflicts with us.

A thread-safe resource is a resource used in different threads that does not cause thread conflicts.

A resource that cannot be changed is thread-safe, for example, a constant:

Const decimal pai = 3.14159265; // C ++: const double pai = 3.14159265;

Because the pai value cannot be changed, using it in different threads will not cause a conflict. In other words, it is no difference between being used simultaneously in different threads and being used in one thread, so this is thread-safe.

Similarly, in. NET, a string instance is also thread-safe, because the string instance cannot be changed in. NET. Once an instance of a string is created, all its properties and method call results are uniquely identified and will never be changed. Therefore, for the. NET class library, refer to the String type: "This type is thread-safe .", Similar types and Assembly types are thread-safe.

However, the string instance is thread-safe, but it does not mean that the string variable is thread-safe. In other words, assume there is a static variable:

Public static string str = "123 ";

Str is NOT thread-safe, because the string instance of the str variable can be modified by any thread.

Consider the following example:

Public static readonly SqlConnection connection = new SqlConnection ("connectionString ");

Although the connection itself is thread-safe, any member of the connection is not thread-safe.

For example, I call the Open method for this connection in a thread and perform the query operation. But at the same time, another thread calls the Close method. At this time, an error occurs.

However, simply using connection without using any of its members, such as if (connection! = Null) There is no thread conflict.

There are still a lot of thread-Safe Resources, so I will not repeat them here.

For. NET Framework members, read-only fields are thread-safe.

So how do we know if the attributes and methods are thread-safe?

Iii. Thread-safe Functions

Because attributes and methods are composed of functions, we will discuss what is a thread-safe function.

As mentioned above, the necessary conditions for thread conflicts are multithreading and sharing resources. If a function does not use any resources that may be shared, thread conflicts, that is, thread security, cannot occur. For example:

Public static int Add (int a, int B ){

Return a + B;

}

All resources used in this function are their own local variables, and the local variables of the function are stored on the stack. Each thread has its own independent stack, therefore, local variables cannot be shared across threads. Therefore, such functions are thread-safe.

However, it is worth noting that the following functions are not thread-safe:

Public static void Swap (ref int a, ref int B) // C ++: void Swap (in & a, int & B)

{

Int c =;

A = B;

B = c;

}

Because of the existence of ref, function parameters are passed in by reference. In other words, a and B seem to be local variables of the function, but they are actually outside the function, if these two items are local variables of another function, there is no problem,

If these two items are global variables (static members), they cannot be ensured that there is no thread conflict. In the previous example, when a and B pass in the function, a copy operation is performed, therefore, whether a and B are global variables or static members does not matter.

Similarly, such functions are not thread-safe:

Public static int Add (INumber a, INumber B) // C ++: int Add (INumber * a, INumber * B );

{

Return a. Number + B. Number;

// C ++: return a-> Number + B-> Number;

}

The reason is that although a and B are internal variables of the function,. number and B. number does not exist. They do not exist on the stack, but are hosted on the stack and may be changed by other threads.

But there are very few functions that only use local variables in the. NET class library, but the. NET class library still has such multi-threaded and secure functions. Why?

Because, even if a function uses shared resources and all the shared resources it uses are thread-safe, this function is thread-safe.

For example:

Private const string connectionString = "…"; Public string GetConnectionString ()

{

Return connectionString;

}

Although this function uses a shared resource connectionString, this function is thread-safe because the resource is thread-safe.

Similarly, we can conclude that if a function only calls thread-safe functions and only uses thread-safe shared resources, this function is thread-safe.

Here is a problem that is easy to ignore, the operator. Not all operators (especially those after overloading) are thread-safe.

Iv. mutex lock

Sometimes we have to deal with thread insecurity. For example, how can we solve this problem by taking the example in the beginning and completing 100 tasks with multiple threads, A simple method is to add a mutex lock to the shared resources. In C #, this is very simple. For example, the first example:

Public static class Environment {public static int count = 0; // Global Counter

}

//... Void ThreadMethod () // method that runs in each thread

{

While (true)

{

Lock (typeof (Environment ))

{

If (count> = 100) // if the task metrics are reached

Break; // interrupt thread execution

DoSomething (); // completes a task

Count ++ ;}}}

Through the mutex lock, when a thread uses the count field, all other threads cannot use it and are blocked and waiting. To avoid thread conflicts.

Of course, such a lock will degrade this multi-threaded program into only one thread running at the same time, so we can advance count ++ to narrow the lock range, as shown in the following figure:

Void ThreadMethod () // method running in each thread {

While (true)

{

Lock (typeof (Environment ))

{

If (count ++> = 100) // if the task indicator is reached

Break; // interrupt thread execution

}

DoSomething (); // completes a task

}}

Finally, let's talk about SyncRoot.

A lot of friends may be confused when using. NET. Why do I need to write the following to lock a container:

Lock (Container. SyncRoot)

Instead of locking (Container)

Because locking a container does not guarantee that the container will not be modified, consider the following container:

Public class Collection {

Private ArrayList _ list;

Public Add (object item)

{

_ List. Add (item );

}

Public object this [int index]

{

Get {return _ list [index];} set {_ list [index] = value ;}

}}

It seems that after you lock it up, everything is fine. No one can modify this container, but in fact this container is actually implemented using an ArrayList instance, if a code segment bypasses the container and directly operates the _ list operation, it is impossible to lock the container object to ensure that the container is not modified.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.