Basic thread concepts,

Source: Internet
Author: User
Tags print object

Basic thread concepts,

Original article: http://blog.sina.com.cn/s/blog_4e61c4290100ndyl.html

 

Introduction

With the promotion of dual-core, quad-core and other multi-core processors, computers with multi-core processors or hyper-threading Single-core processors have become very common. programming technologies based on multi-core processing have also attracted widespread attention from programmers. One of the important aspects is to build multi-threaded applications (because developers cannot fully utilize the powerful performance of multi-core computers without using multithreading ).

This article is intended to build a single-core computer-based multi-threaded application. It aims to introduce the basic concepts and meanings related to multithreading and how to use the System. threading namespace class, delegate, and BackgroundWorker component to build multi-threaded applications.

This article will be satisfied if it can be used to attract others who are new to multithreading. Of course, I am not easy to learn. It is inevitable that there will be deficiencies or errors in this article. Please kindly advise me more.

  1. Understand Multithreading

The application we generally understand is *. exe file, when running *. after the exe application, the system will allocate some space for the program in the memory and load some resources required by the program. In fact, this can be called creating a process. You can use the Windows Task Manager to view information about the process, such as the image name, user name, memory usage, and PID (unique process ID,.

The thread is only a basic execution unit in the process. An application usually has only one program entry, such:

[STAThread]

Static void Main () // Main entry point of the application

{

Application. EnableVisualStyles ();

Application. SetCompatibleTextRenderingDefault (false );

Application. Run (new MainForm ());

}

A process contains a thread that enters this entry, which is called the main thread. The feature [STAThread] indicates that the default thread model of the application is a single thread unit (for information, see http://msdn.microsoft.com/en-us/library/system.stathreadattribute (VS.71). aspx ). A process that contains only one main thread is thread-safe, which is equivalent to a program with only one working thread. Only after the previous task is completed can the subsequent task be executed.

However, when a program processes a very time-consuming task, such as outputting a large file or remotely accessing the database, the form interface program basically does not respond to the user, menus and buttons are useless. Because the RESPONSE event of the control on the form also needs to be executed by the main thread, while the main thread is busy with other tasks, the control RESPONSE event can only be queued until the main thread is busy and then executed.

To overcome this defect of a single thread, Win32 API allows the main thread to create another thread, but both the main thread and the secondary thread are independent execution units in the process, the shared data can be accessed at the same time, so that the concept of Multithreading is introduced.

I believe that we should have a more emotional understanding of multithreading. However, I would like to remind you that single-core computer-based multithreading is only a blind eye for the operating system (but it will not interfere with our understanding of the idea of building multi-threaded applications ), it cannot shorten the time to complete all tasks, but sometimes it will reduce performance and prolong time by using too many threads. This is because for a single CPU, only one thread can be executed per unit time (also called a time slice), that is, only one task can be done. When the time slice of a thread is used up, the system suspends the thread and executes another thread in the next time, the CPU uses time slice as the interval to execute operations alternately among multiple threads (in fact, this operation is also related to the priority of each thread, and a high level will give priority to processing ). Due to the short switching interval, the illusion that each thread is "simultaneously" working is generated. If the number of threads is too large, the current State data of the thread should be recorded when the system suspends the thread, this will inevitably reduce the overall performance of the program. But for these, multi-core computers can improve program execution efficiency in essence (truly working at the same time.

  2. asynchronous thread synchronization

The thread-based task execution methods can be divided into thread synchronization and thread Asynchronization. For ease of understanding, "synchronous thread" is used in the subsequent description to refer to threads related to thread synchronization. Similarly, "asynchronous thread" is used to represent threads related to thread Asynchronization.

Thread Asynchronization solves the problem that interface controls cannot be used when time-consuming tasks are executed. For example, if you create a thread to specifically execute time-consuming tasks, and other tasks such as interface control response are handed over to another thread for execution (usually executed by the main thread ). In this way, switching between two threads within a short time (time slice) by the thread scheduler can simulate the effect of multiple tasks being executed simultaneously.

Thread Asynchronization is usually performed by creating multiple threads to execute multiple tasks, and multiple working lines start working at the same time. Similar to the simultaneous development of multiple vehicles on a wide road, they do not interfere with each other (readers must understand that there is no "at the same time" in essence, and it is only a blind eye for the operating system. However, this blind-eye method is useful for improving the interaction between our programs and users, and enhancing the program friendliness, isn't it ).

Before introducing thread synchronization, we first introduce a concept closely related to this-concurrency issues.

As mentioned above, threads are independent execution units that can access Shared data. That is to say, in a program with multiple threads, each thread can access the same shared data. If you think about it, you will find that there may be problems: Because the thread scheduler will randomly suspend a thread (switching between threads described earlier ), so when thread a's access to shared data D (modification, deletion, and other operations) is suspended, and thread B Just accesses data D, then thread B accesses an unstable data. In this way, it is very difficult to find bugs. Because they occur randomly, the results are unpredictable, and such bugs are difficult to reproduce and debug. This is the concurrency issue.

To solve the concurrency problem caused by multi-threaded joint access to a shared resource (also known as mutex access), thread synchronization came into being. The mechanism of thread synchronization is simply to prevent multiple threads from simultaneously accessing a shared resource. The method is very simple. Mark the part of the Code that accesses a shared resource. When the program runs to a marked place, CLR (the specific content can be ignored first, as long as you know that it can be controlled) adjust each thread: if an existing thread is accessing a resource, the CLR suspends other threads that access the resource until the previous thread ends access to the resource. This ensures that only one thread accesses the resource at a time. For example, if a resource is placed on an isolated island connected to only one zhuanqiao, if you want to use the resource, You have to queue up one by one. The previous one is back, and the next one is back, the previous one did not return, and the latter was on standby.

Here we will simply describe the basic concepts and principles, so that we won't be confused when looking at the subsequent programs. The following section describes how to write code.

 

 

  3. Create a multi-threaded Application

Here is a simple description: The following describes how to use System. threading namespace class, delegate and BackgroundWorker component three different methods to build a multi-threaded application, specifically from two aspects: thread asynchronous and thread synchronization.

3.1 Build through the class of the System. Threading namespace

On the. NET platform, the System. Threading namespace provides many types to build multi-threaded applications. It can be said that it is designed for multi-threaded services. Because this article only reminds me of the role of "throwing bricks and jade", it will not be discussed too much or too deep, mainly using the System. Threading. Thread class.

First, let's start with a small example related to the System. Threading. Thread class. The Code is as follows. for explanations, see the notes:

Using System;

Using System. Threading; // introduce the System. Threading namespace

Namespace MultiThread

{

Class Class

{

Static void Main (string [] args)

{

Console. writeLine ("*************** display information about the current thread *************");

// Declare the thread variable and assign a value to the current thread

Thread primaryThread = Thread. CurrentThread;

// Assign the thread name

PrimaryThread. Name = "main thread ";

// Display thread-related information

Console. WriteLine ("thread Name: {0}", primaryThread. Name );

Console. WriteLine ("is the thread started? {0} ", primaryThread. IsAlive );

Console. WriteLine ("thread Priority: {0}", primaryThread. Priority );

Console. WriteLine ("thread status: {0}", primaryThread. ThreadState );

Console. ReadLine ();

}

}

}

The output result is as follows:

* ************ Display information about the current thread *************

Thread name: main thread

Does the thread start? True

Thread priority: Normal

Thread status: Running

I don't want to explain the above Code too much. I just want to say that Thread. CurrentThread gets the Thread that executes the current code.

3.1.1 asynchronous call thread

The foreground thread and background thread are described here. The foreground thread can block the termination of the application, and it will not completely close the application until all foreground threads are terminated. For background threads, when all foreground threads terminate, background threads are automatically terminated, regardless of whether the background threads are executing tasks. By default, all threads created using the Thread. Start () method are automatically foreground threads. When the IsBackground attribute of a Thread is set to true, the Thread is converted to a background Thread.

Next, let's take a look at an example. This example creates a thread to execute the task of printing numbers, while the main thread does other things. The two do not interfere with each other.

Using System;

Using System. Threading;

Using System. Windows. Forms;

Namespace MultiThread

{

Class Class

{

Static void Main (string [] args)

{

Console. writeLine *****************");

// Main thread, because the thread currently executing Main () is obtained

Thread primaryThread = Thread. CurrentThread;

PrimaryThread. Name = "main thread ";

Console. WriteLine ("-> {0} is executing the Main function Main (). ", Thread. CurrentThread. Name );

// Thread, which points to the PrintNumbers () method

Thread SecondThread = new Thread (new ThreadStart (PrintNumbers ));

SecondThread. Name = "";

// The method pointed to when the thread starts to execute

SecondThread. Start ();

// At the same time, the main thread executes other tasks in the main function

MessageBox. Show ("the task in the main function is being executed .... "," The main thread is working ...");

Console. ReadLine ();

}

// Method for printing numbers

Static void PrintNumbers ()

{

Console. WriteLine ("-> {0}: Execute the print number function PrintNumber ()", Thread. CurrentThread. Name );

Console. WriteLine ("print number :");

For (int I = 0; I <10; I ++)

{

Console. Write ("{0},", I );

// The Sleep () method causes the current thread to wait for the specified duration to be executed. Here, it mainly imitates the print task.

Thread. Sleep (2000 );

}

Console. WriteLine ();

}

}

}

After the program runs, a window pops up, And the console window is constantly displaying numbers.

Output result:

*****************

-> The Main thread is executing the Main function Main ().

-> The number function PrintNumber () is executed by the next thread ()

Print numbers:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

 

Previous Page [1] [2] [3] [4] [5] [6] Next page

Welcome to The. NET community forum and interact with 2 million technical staff> enter

 

Here we will explain Thread SecondThread = new Thread (new ThreadStart (PrintNumbers. In fact, ThreadStart is a delegate in the System. Threading namespace. Its declaration is public delegate void ThreadStart (), pointing to a method without parameters and with a NULL return value. Therefore, when ThreadStart is used, the corresponding thread can only call a method without parameters and the return value is null. Do you have to point to methods with parameters? In System. there is also a ParameterizedThreadStart delegate in the Threading namespace. Its declaration is public delegate void ParameterizedThreadStart (object obj), which can point to Methods containing object type parameters, do not forget that the object is a parent class of all types. With this class, you can pass many parameters by creating various custom types, such as structures and classes, here we will not illustrate it.

3.1.2 concurrency Problems

Here we will use an example to show you the concurrency problems mentioned above, and then introduce thread synchronization.

Using System;

Using System. Threading;

Namespace MultiThread1

{

Class Class

{

Static void Main (string [] args)

{

Console. WriteLine ***************");

// Create a print object instance

Printer printer = new Printer ();

// Declare an array containing five thread objects

Thread [] threads = new Thread [10];

For (int I = 0; I <10; I ++)

{

// Point every thread to the printer's PrintNumbers () method

Threads [I] = new Thread (new ThreadStart (printer. PrintNumbers ));

// Number each thread

Threads [I]. Name = I. ToString () + "No. Thread ";

}

// Start executing all threads

Foreach (Thread t in threads)

T. Start ();

Console. ReadLine ();

}

}

// Print

Public class Printer

{

// Method for printing numbers

Public void PrintNumbers ()

{

Console. WriteLine ("-> {0} is executing the print task. Start printing the number:", Thread. CurrentThread. Name );

For (int I = 0; I <10; I ++)

{

Random r = new Random ();

// In order to increase the probability of conflict and make each thread wait for a random length

Thread. Sleep (2000 * r. Next (5 ));

// Print numbers

Console. Write ("{0}", I );

}

Console. WriteLine ();

}

}

}

In the above example, the 10 threads generated by the main thread simultaneously access the printer method of the same object instance PrintNumbers (), because shared resources are not locked (note, this refers to the console ), therefore, before PrintNumbers () is output to the console, the thread that calls PrintNumbers () may be suspended, but it does not know when (or whether) It will be suspended, resulting in unpredictable results. The following are two different results (of course, the reader's running results may be in other situations ).

Scenario 1

Scenario 2

 

 

 

3.1.3 Thread Synchronization

The access method of thread synchronization is also called blocking call, that is, the thread is suspended if no task is executed and no return is returned. You can use the lock keyword in C #. The code in the scope of this keyword will be thread-safe. The lock keyword defines a mark, which must be obtained when the thread enters the lock range. When locking a private method of an instance-level object, you can use the reference of the object where the method itself is located. Modify the print class Printer in the above example and add the lock keyword, the Code is as follows:

// Print

Public class Printer

{

Public void PrintNumbers ()

{

// Use the lock keyword. The code for locking d is thread-safe.

Lock (this)

{

Console. WriteLine ("-> {0} is executing the print task. Start printing the number:", Thread. CurrentThread. Name );

For (int I = 0; I <10; I ++)

{

Random r = new Random ();

// In order to increase the probability of conflict and make each thread wait for a random length

Thread. Sleep (2000 * r. Next (5 ));

// Print numbers

Console. Write ("{0}", I );

}

Console. WriteLine ();

}

}

}

}

The execution result after synchronization is as follows:

You can also use the Monitor class in the System. Threading namespace for synchronization. The two have the same connotation, but the Monitor class is more flexible. I will not discuss it too much here. The Code is as follows:

// Print

Public class Printer

{

Public void PrintNumbers ()

{

Monitor. Enter (this );

Try

{

Console. WriteLine ("-> {0} is executing the print task. Start printing the number:", Thread. CurrentThread. Name );

For (int I = 0; I <10; I ++)

{

Random r = new Random ();

// In order to increase the probability of conflict and make each thread wait for a random length

Thread. Sleep (2000 * r. Next (5 ));

// Print numbers

Console. Write ("{0}", I );

}

Console. WriteLine ();

}

Finally

{

Monitor. Exit (this );

}

}

}

The output result is the same as the preceding one.

3.2 build multi-threaded applications by Delegation

When reading the following content, you must have a certain understanding of the delegation. If you are not clear about it, we recommend that you refer to the delegation and events in C # In zhangziyang of the blog garden. for more information about delegation and events, see http://www.cnblogs.com/jimmyzhang/archive/2007/09/23/903360.html.

Here is a simple example of delegation. For more information, see note:

Using System;

Namespace MultiThread

{

// Define a delegate to a function that contains two int parameters and returns an int value.

Public delegate int AddOp (int x, int y );

Class Program

{

Static void Main (string [] args)

{

// Create an AddOp object p pointing to the Add () method

AddOp pAddOp = new AddOp (Add );

// Use the delegate indirect call Method Add ()

Console. WriteLine ("10 + 25 = {0}", pAddOp (10, 5 ));

Console. ReadLine ();

}

// Sum function

Static int Add (int x, int y)

{

Int sum = x + y;

Return sum;

}

}

}

The running result is:

10 + 25 = 15

 

 

 

3.2.1 asynchronous thread

First, I will not explain the asynchronous or synchronous parameter transfer and return value of the delegate thread here. It is just a general beginning, if you have time later, write another article about parameter passing and return value in multithreading.

Note that the preceding example shows that the summation method Add () is called directly using the delegated instance pAddOp (10, 5 (). Obviously, this method is executed by the main thread. However, there are two other methods in the delegate type: BeginInvoke () and EndInvoke (). The following describes how to change the above example as follows:

Using System;

Using System. Threading;

Using System. Runtime. Remoting. Messaging;

Namespace MultiThread

{

// Declare the delegate to a function that contains two int parameters and returns the int type.

Public delegate int AddOp (int x, int y );

Class Program

{

Static void Main (string [] args)

{

Console. WriteLine ("******** entrusting asynchronous threads to" simultaneously "Work *********");

// Display the unique identifier of the main thread

Console. WriteLine ("the Thread ID of the Main Thread that calls Main () is: {0}.", Thread. CurrentThread. ManagedThreadId );

// Direct the delegated instance to the Add () method

AddOp pAddOp = new AddOp (Add );

// Start the delegate thread call. The type returned by the delegate BeginInvoke () method is IAsyncResult,

// Contains the value returned by the delegate pointing to the end of the method, and is also an EndInvoke () method parameter

IAsyncResult iftAR = pAddOp. BeginInvoke (10, 10, null, null );

Console. WriteLine ("" nMain () method to execute other tasks... "n ");

Int sum = pAddOp. EndInvoke (iftAR );

Console. WriteLine ("10 + 10 = {0}.", sum );

Console. ReadLine ();

}

// Sum Method

Static int Add (int x, int y)

{

// Indicates the thread ID that calls this method. ManagedThreadId is the unique identifier of the thread.

Console. WriteLine ("the Thread ID for calling the summation method Add () is: {0}.", Thread. CurrentThread. ManagedThreadId );

// Simulate a process and stay for 5 seconds

Thread. Sleep (5000 );

Int sum = x + y;

Return sum;

}

}

}

The running result is as follows:

* ****** Entrusting asynchronous threads to "work simultaneously *********

The thread ID of the Main thread that calls Main () is: 10.

Execute other tasks in the Main () method ........

The thread ID for calling the Sum Method Add () is: 7.

10 + 10 = 20.

3.2.2 Thread Synchronization

Thread Synchronization in the delegate mainly involves the following two null parameters in the pAddOp. BeginInvoke (10, 10, null, null) method used above. For details, refer to relevant materials. The code here is as follows. for explanations, see the code Annotations:

Using System;

Using System. Threading;

Using System. Runtime. Remoting. Messaging;

Namespace MultiThread

{

// Declare the delegate to a function that contains two int parameters and returns the int type.

Public delegate int AddOp (int x, int y );

Class Program

{

Static void Main (string [] args)

{

Console. WriteLine ("******* thread synchronization," blocking "call, two threads working *********");

Console. WriteLine ("Main () invokee on thread {0}.", Thread. CurrentThread. ManagedThreadId );

// Direct the delegated instance to the Add () method

AddOp pAddOp = new AddOp (Add );

IAsyncResult iftAR = pAddOp. BeginInvoke (10, 10, null, null );

// Determine whether the delegate thread has completed the task,

// If it is not completed, the main thread will do other things.

While (! IftAR. IsCompleted)

{

Console. WriteLine ("Main () method working .......");

Thread. Sleep (1000 );

}

// Obtain the returned value

Int answer = pAddOp. EndInvoke (iftAR );

Console. WriteLine ("10 + 10 = {0}.", answer );

Console. ReadLine ();

}

// Sum Method

Static int Add (int x, int y)

{

// Indicates the thread ID that calls this method. ManagedThreadId is the unique identifier of the thread.

Console. WriteLine ("the Thread ID for calling the summation method Add () is: {0}.", Thread. CurrentThread. ManagedThreadId );

// Simulate a process and stay for 5 seconds

Thread. Sleep (5000 );

Int sum = x + y;

Return sum;

}

}

}

 

 

The running result is as follows:

* ****** Thread synchronization, "blocking" calls, two threads working *********

Main () invokee on thread 10.

The Main () method is working .......

The thread ID for calling the Sum Method Add () is: 7.

The Main () method is working .......

The Main () method is working .......

The Main () method is working .......

The Main () method is working .......

10 + 10 = 20.

3.3BackgroundWorker component

The BackgroundWorker component is located in the toolbox to easily create a program with asynchronous threads. Create a Windows Forms Application on the following page:

The Code is as follows:

Private void button#click (object sender, EventArgs e)

{

Try

{

// Obtain the input number

Int numOne = int. Parse (this. textBox1.Text );

Int numTwo = int. Parse (this. textBox2.Text );

// Instantiate the parameter class

AddParams args = new AddParams (numOne, numTwo );

// Call RunWorkerAsync () to generate the background thread and input parameters

This. backgroundWorker1.RunWorkerAsync (args );

}

Catch (Exception ex)

{

MessageBox. Show (ex. Message );

}

}

// The newly generated backgroundWorker thread starts working.

Private void backgroundworker=dowork (object sender, DoWorkEventArgs e)

{

// Obtain the input AddParams object

AddParams args = (AddParams) e. Argument;

// Stay for 5 seconds to simulate time-consuming tasks

Thread. Sleep (5000 );

// Return Value

E. Result = args. a + args. B;

}

// This event is triggered after the code in the DoWork of backgroundWorker1 is executed.

// At the same time, the execution result will be included in the RunWorkerCompletedEventArgs Parameter

Private void backgroundworkerappsrunworkercompleted (object sender, RunWorkerCompletedEventArgs e)

{

// Display the operation result

MessageBox. Show ("running Result:" + e. Result. ToString (), "Result ");

}

}

// Parameter class, which only serves to record and PASS Parameters

Class AddParams

{

Public int a, B;

Public AddParams (int numb1, int numb2)

{

A = numb1;

B = numb2;

}

}

Note: While calculating the result, the form can be moved freely or enter information in the text box again. This indicates that the thread generated by the main thread and the backgroundWorker component is asynchronous.

4. Summary

Starting from the relationship between threads, processes, and applications, this article introduces some basic concepts about multithreading and describes thread Asynchronization, thread synchronization, and concurrency. Finally, this article introduces how to build multi-threaded applications by using the class, delegate, and BackgroundWorker components of the System. Threading namespace.

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.