Linux multithreaded programming

Source: Internet
Author: User

--an example of this article expands on the operation of threads under Linux, the synchronization of multithreading, and mutual exclusion.

Objective

Thread? Why are there processes that require threads, and what is the difference between them? What are the advantages of using threads? There are also some details about multi-threading programming, such as how threads are synchronized and mutually exclusive, and these things are described in this article. Here is an interview question:

Are you familiar with POSIX multithreaded programming technology? As familiar, write the program to complete the following functions: 1) have an int type global variable G_flag initial value of 0;2) Start thread 1 in the main line call, print "This is Thread1" and set the G_flag to 13) in the main line called Thread 2, print "This is Thread2 ", and set G_flag to 24) line program 1 requires thread 2 exit before exiting 5) The main thread exits when it detects that G_flag has changed from 1 to 2, or from 2 to 1

We started this article with this question, and after that, everyone would do it. The framework of this article is as follows:

    • 1. Process and Thread
    • 2. Reasons for using threads
    • 3. Functions related to threading operations
    • 4. Mutual exclusion between threads
    • 5. Synchronization between threads
    • 6. Final Test Code
1. Process and Thread

A process is an instance of the execution of a program, which is the collection of data structures to what extent the program has performed. from the kernel point of view, the purpose of the process is to assume the basic unit of allocating system resources (CPU time, memory, etc.). A thread is an execution flow of a process that is the basic unit of CPU dispatch and dispatch, which is a smaller unit that can run independently than a process. A process consists of several threads (a user program with many relatively independent execution flows that shares most of the data structures of the application), and the threads share all the resources owned by the process with other threads that belong to one process.

"Process-the smallest unit of resource allocation, thread-the smallest unit of program execution"

The process has a separate address space, and after a process crashes, it does not affect other processes in protected mode, and the thread is just a different execution path in a process. Thread has its own stack and local variables, but the thread does not have a separate address space, a thread dead is equal to the entire process to die, so the multi-process program is more robust than multi-threaded programs, but in the process of switching, the cost of large resources, efficiency is worse. But for some concurrent operations that require simultaneous and shared variables , only threads can be used, and processes cannot be used.

2. Reasons for using threads

From the above we know the difference between the process and the thread, in fact, these differences are the reason why we use threads. In general , the process has a separate address space, and the thread does not have a separate address space (the address space of the thread sharing process within the same process).

One of the reasons to use multithreading is that it is a very "frugal" multi-tasking approach compared to the process. We know that under the Linux system, starting a new process must be assigned to its own address space, creating numerous data tables to maintain its code snippets, stack segments, and data segments, which is an "expensive" multi-tasking way of working. While running on multiple threads in a process that use the same address space, sharing most of the data, starting a thread is much less than the space it takes to start a process, and the time it takes to switch between threads is much less than the time it takes to switch between processes. According to statistics, in general, the cost of a process is about 30 times times the cost of a thread, of course, on a specific system, this data may be significantly different.

The second reason to use multithreading is the convenient communication mechanism between threads. For different processes, they have independent data space, it is not only time-consuming, but also inconvenient to transmit the data only by means of communication . Threads do not, because data space is shared between threads in the same process, so that the data of one thread can be used directly by other threads, which is not only fast, but also convenient. Of course, the sharing of data also brings some other problems, some variables can not be modified by two threads at the same time, some of the sub-programs declared as static data more likely to have a catastrophic attack on the multi-threaded program, these are the most important to write a multi-thread programming.

In addition to the advantages mentioned above, not compared with the process, multi-threaded procedure as a multi-tasking, concurrent work, of course, the following advantages:

    • Improve application responsiveness. This is especially meaningful to the graphical interface program, when an operation takes a long time, the entire system waits for this operation, the program does not respond to the keyboard, mouse, menu operation, and the use of multi-threading technology, the time-consuming operation (consuming) into a new thread, can avoid this embarrassing situation.
    • Make multi-CPU systems more efficient. The operating system guarantees that when the number of threads is not greater than the number of CPUs, different threads run on different CPUs.
    • Improve the program structure. A long and complex process can be considered to be divided into multiple threads and become a separate or semi-independent part of the run, which facilitates understanding and modification.

From the function call, process creation uses the fork () operation, and thread creation uses the Clone () operation. Master Richard Stevens said:

Fork is expensive. Memory is copied from the parent to the child, all descriptors be duplicated in the child, and so on. Current implementations use a technique called copy-on-write which avoids a copy of the parent's data space to the child Until the child needs its own copy. But, regardless of the optimization, fork is expensive.

IPC is required-pass information between the parent and child after the fork. Passing information from the parent to the child before the fork was easy, since the child starts with a copy of the parent ' s data space and with a copy of the ' The parent ' s descriptors. But, returning information from the child to the parent takes more work.

Threads help with both problems. Threads is sometimes called lightweight processes since a thread is "lighter weight" than a process. That's, thread creation can be 10~100 times faster than process creation.

All threads within a process share the same global memory. This makes the sharing of information easy between the threads, but along with this simplicity comes the problem of SYNCHR Onization.

3. Functions related to threading operations
#include <pthread.h> int pthread_create (pthread_t *tid, const pthread_attr_t *attr, void * (*FUNC) (void *), void *ar  g) int Pthread_join (pthread_t tid, void * * status);p thread_t pthread_self (void); int Pthread_detach (pthread_t tid); void Pthread_exit (void *status);

Pthread_create is used to create a thread that successfully returns 0, otherwise returns EXXX (a positive number).
pthread_t *tid: The type of thread ID is pthread_t, usually an unsigned integer, returned by a *tid pointer when the call Pthread_create succeeds.
Const pthread_attr_t *ATTR: Specifies the properties of the creation thread, such as the thread priority, the initial stack size, whether it is a daemon, and so on. The default value can be used with NULL, which is usually the case with default values.
void * (*FUNC) (void *): function pointer func, which specifies the function to be executed after the new thread is created.
void *arg: The parameters of the function that the thread will execute. If you want to pass multiple parameters, encapsulate them in a struct.


The pthread_join is used to wait for a thread to exit, return 0 successfully, or return exxx (a positive number).
pthread_t tid: Specifies the thread ID to wait for
void * Status: If it is not NULL, then the return value of the thread is stored in the space where status is pointing (that is why status is a level two pointer!). This is also known as the "value-result" parameter.

The pthread_self is used to return the ID of the current thread.

Pthread_detach is used to specify that the thread becomes detached, as if the process were out of terminal and turned into a background process. Successful return 0, otherwise return exxx (positive). A thread that becomes detached, and if the thread exits, all its resources are freed. If it is not a detached state, the thread must retain its thread ID, exiting the state until other threads call it pthread_join.

Process is similar, this is also when we open the process manager, found that there are many zombie process reasons! is also why must have zombie this process state.

Pthread_exit is used to terminate a thread, you can specify a return value so that other threads get the return value of the thread through the Pthread_join function.
void *status: Refers to the return value of the thread termination.

Once we know these functions, we try to complete the first issue of this article:

1) There is an int type global variable G_flag initial value of 0;2) starting thread 1 in the mainline call, printing "This is Thread1" and setting the G_flag to 13) starting thread 2 in the mainline call, printing "This is Thread2" and g_ Flag set to 24) line program 1 requires thread 2 to exit before exiting

These 4 points are very simple!!! Not just call pthread_create to create the thread, and then wait for thread2 to end in Thread1.

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <errno.h> #include < Unistd.h>int G_flag = 0;void* thread1 (void*); void* thread2 (void*); int main (int argc, char **argv) {printf ("Enter main\ n ");p thread_t tid1,tid2;int res1 = 0;int Res2 = 0;res2 = Pthread_create (&tid2, NULL, thread2, NULL); if (res2! = 0) {Prin TF ("%s:%d\n", __func__, Strerror (Res2));} Res1 = Pthread_create (&tid1, NULL, Thread1, &AMP;TID2); if (res1! = 0) {printf ("%s:%d\n", __func__, Strerror (res1));} Sleep (3);p rintf ("Leave main\n"); exit (0);} void* thread1 (void *arg) {printf ("Enter thread1\n");p rintf ("This was Thread1, g_flag:%d, thread1 ID is%u\n", G_flag, (Unsig Ned int) pthread_self ()); G_flag = 1;printf ("This was Thread1, g_flag:%d, thread1 ID is%u\n", G_flag, (unsigned int) pthread_ Self ());p thread_join (* (pthread_t *) arg, NULL);p rintf ("Leave thread1\n");p thread_exit (0);} void* thread2 (void *arg) {printf ("Enter thread2\n");p rintf ("This was thread2, g_flag:%d, thread2 ID is%u\n", G_flag, (unsigned int) pthread_self ()), G_flag = 2;printf ("This was Thread1, g_flag:%d, thread2 ID is%u\n", G_flag, (unsigned int) Pthread_self ()); Sleep (1);p rintf ("Leave thread2\n");p thread_exit (0);}

To compile the code:

$ gcc-pthread-o Test test.c
You must have noticed that we called pthread_exit before the thread function Thread1 () and Thread2 () were executed. What if I call exit () or return? Try it yourself! Pthread_exit () is used for thread exit, and you can specify a return value so that other threads get the return value of the thread through the Pthread_join () function. Return is the function return, only the thread function return, the thread will exit. Exit is the process exit, and if exit is called in the thread function, all functions in the process will exit!
4. Mutual exclusion between threads

The above code seems to be a good solution to the problem of the front 4 point requirements, not really!!! Because G_flag is a global variable, thread thread1 and thread2 can operate on it at the same time, requiring it to be lock-protected and Thread1 and thread2 to be mutually exclusive. Here we describe how to lock protection-mutex.

Mutex: Use a mutex (mutex) to enable the thread to execute sequentially. Typically, mutexes synchronize multiple threads by ensuring that only one thread executes the critical segment of code at a time. Mutexes can also protect single-threaded code.

The associated operation function for the mutex is as follows:

#include <pthread.h> int Pthread_mutex_lock (pthread_mutex_t * mptr); int Pthread_mutex_unlock (pthread_mutex_t * mptr); Both return:0 if OK, positive exxx value On Error

Before the operation of the critical resources need to Pthread_mutex_lock first lock, after the operation Pthread_mutex_unlock again unlocked. And before that, you need to declare a variable of type pthread_mutex_t, which is used as an argument for the previous two functions. See section 5th for specific codes.

5. Synchronization between threads

5th-The main thread exits when it detects that G_flag has changed from 1 to 2, or from 2 to 1. You need to use thread synchronization technology! A conditional variable is required for thread synchronization.

Linux multithreaded programming

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.