Detailed analysis of the Linux multi-threaded programming

  Thread? Why has the process also need to thread it, what are their differences? What advantages does using threads? There are multi-threaded programming some of the details, such as how the synchronization between threads, mutual exclusion, these things will be covered in this article . I see such a face questions:

  ? Are familiar with the POSIX multithreaded programming techniques such as familiar to program the following functions:

  1) there is a global variable of type int g_Flag initial value of 0;

  2) In the main thread 1, said the start, print "this is thread1", and g_Flag set to 1

  3) in the main line, said start thread 2, print "this is thread2", and g_Flag to 2

  4) line 1 need to exit the program after the thread exits 2

  5) When the main thread exits we detected g_Flag from 1 to 2, or from 2 to 1 to start with this question in this article, after the end, everyone would do it. Frame are as follows:

  1, process and thread

  2, using threads of reason

  3, functions related to the operation of the thread

  Mutual exclusion between 4 threads

  5 synchronization between threads

  6, the final code questions

  1, process and thread

  Process is an instance when the program is executed, that it is the implementation of the program has been to bring together what extent the data structure. From the kernel's point of view, the purpose of the process is to serve as the basic unit of allocation of system resources (CPU time, memory, etc.).

  A thread is a flow execution process, is the basic unit of CPU scheduling and dispatching, which is smaller than the process of the basic unit can operate independently. (Most of the data structure has many relatively independent of the user program execution flow of shared application) a process consisting of several threads, thread and other threads share the process belong to a process that is owned by all of the resources.

  "Process - the smallest unit of resource allocation, thread - the smallest unit of program execution" process has a separate address space, after a process crashes, will not have an impact on other processes in protected mode, and the thread is just a process different execution paths. Thread has its own stack and local variables, but the thread does not have a separate address space, a thread to die is tantamount to the whole process dies, so the program than multi-process multi-threaded programs robust, but in the process of switching, resource-intensive than big, efficiency is worse. But for some of the requirements at the same time and have to share the concurrent operation of certain variables, only with thread, the process can not be used.

  2, using threads of reason

  From the above we know the difference between processes and threads, in fact, these differences also is the reason we use threads. General is: The process has a separate address space, threads no separate address space (threads share the process in the same process address space). (The following is an excerpt from a multithreaded programming under Linux)

  One reason to use multiple threads and processes are compared, it is a very "frugal" multitasking operating mode. We know that in the Linux system, start a new process must be assigned to its separate address space, the establishment of a large number of data tables to maintain its code segment, stack and data segments, this is an "expensive" multi-tasking Way of working. While running on multiple threads within a process, using the same address space between each other, share most of the data, start a thread space it takes far less than it takes to start a process space, and, switching between threads to each other the time required is far less than the time required to switch between processes. According to statistics, in general, the cost of a process is about 30 times the cost of a thread, of course, on the specific system, this data may have a greater difference.

  Reason two is the use of multi-threading mechanism to facilitate communication between threads. For different processes, they have separate data space, data transfer can only be carried out by means of communication, this approach is not only time-consuming and inconvenient. Thread is not the case, due to the shared data space between threads in the same process, so the data a thread can be directly used for the other threads, it is not only fast, but also convenient. Of course, sharing data has also brought a number of other issues, some variables can not be modified by two threads at the same time, some routine statements are more likely to have disastrous blow to the multi-threaded program as static data, which are being is where the time of writing multithreaded programs most in need of attention.

  Apart from the above mentioned advantages, and the process does not compare, multi-threaded program as a multi-task, complicated by the way, of course, has the following advantages:

  Improve application response. This program is especially meaningful graphical interface, when an operation takes a long time, the whole system will wait for the operation, this procedure will not respond to keyboard, mouse, menus, and the use of multi-threading technology, will take a long operation (time consuming) placed in a new thread, you can avoid this embarrassing situation.

  The multi-CPU system more efficient. The operating system ensures that when the number of threads is not greater than the number of CPU, running on different threads on different CPU.

  Improve program structure. A long and complex process can be considered divided into multiple threads into several independent or semi-independent part of the run, such a program would be beneficial to understand and modify.

  =============================

  From the function call, the process created using the fork () operation; thread created using clone () operation. Richard Stevens master said this:

  fork is expensive. Memory is copied from the parent to the child, all descriptors are 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 this optimization, fork is expensive.

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

  Threads help with both problems. Threads are sometimes called lightweight processes since a thread is "lighter weight" than a process. That is, 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 synchronization.

  =============================

  3, functions related to the operation of the thread

  #include

  int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func) (void *), void *arg);

  int pthread_join (pthread_t tid, void ** status);

  pthread_t pthread_self (void);

  int pthread_detach (pthread_t tid);

  void pthread_exit (void *status);

  pthread_create creates a thread for the successful return 0, otherwise Exxx (a positive number).

  pthread_t * tid: type thread id is pthread_t, usually unsigned integer when calling pthread_create successful, the pointer returned by * tid.

  const pthread_attr_t * attr: attribute specifies the creation of threads, such as thread priority, the initial stack size, whether the daemons. You can use NULL to use the default values, we are usually use the default value.

  void * (* func) (void *): function pointer func, specify when the new thread is created after the function to be performed.

  void * arg: argument to the function thread execution. If you want to pass a plurality of parameters, place them in a package structure.

  pthread_join waiting for a thread to exit, the successful return 0, otherwise Exxx (a positive number).

  pthread_t tid: Specifies the thread ID to wait

  void ** status: If not NULL, then thread the return value is stored in the space pointed to by status (which is why the status is the reason that only two pointer parameter is also known as "value - the result of" parameter!).

  pthread_self used to return the ID of the current thread.

  pthread_detach is used to specify the thread becomes separated from the state, as the process from the terminal becomes a background process is similar. Successful return 0, otherwise Exxx (a positive number). Into a separate state of thread, if the thread exits, it's all the resources will be fully released. And if it is not separated from the state, the thread must retain its thread ID, exit status until another thread it calls pthread_join.

  The process is similar, and this is when we open the process manager, I found there are many reasons a zombie! This is why there must be a zombie process state. pthread_exit thread to terminate, return values ​​can be specified, so that other threads the thread acquires the return value of the function by pthread_join.

  void * status: Pointer thread termination return value.

  Know these functions later, we are trying to accomplish question this article begins:

  1) there is a global variable of type int g_Flag initial value of 0;

  2) In the main thread 1, said the start, print "this is thread1", and g_Flag set to 1

  3) in the main line, said start thread 2, print "this is thread2", and g_Flag to 2

  This is a very simple thing !!! 3:00 not that call pthread_create to create threads. code show as below:

  /*

  * 1) there is a global variable of type int g_Flag initial value of 0;

  *

  * 2) in the main thread 1, said the start, print "this is thread1", and g_Flag set to 1

  *

  * 3) in said main thread start 2, print "this is thread2", and g_Flag to 2

  *

  */

  #include

  #include

  #include

  #include

  #include

  int g_Flag=0;

  void* thread1(void*);

  void* thread2(void*);

  /*

  * when program is started, a single thread is created, called the initial thread or main thread.

  * Additional threads are created by pthread_create.

  * So we just need to create two thread in main().

  */

  int main(int argc, char** argv)

  {

  printf("enter main\n");

  pthread_t tid1, tid2;

  int rc1=0, rc2=0;

  rc2 = pthread_create(&tid2, NULL, thread2, NULL);

  if(rc2 != 0)

  printf("%s: %d\n",__func__, strerror(rc2));

  rc1 = pthread_create(&tid1, NULL, thread1, &tid2);

  if(rc1 != 0)

  printf("%s: %d\n",__func__, strerror(rc1));

  printf("leave main\n");

  exit(0);

  }

  /*

  * thread1() will be execute by thread1, after pthread_create()

  * it will set g_Flag = 1;

  */

  void* thread1(void* arg)

  {

  printf("enter thread1\n");

  printf("this is thread1, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());

  g_Flag = 1;

  printf("this is thread1, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());

  printf("leave thread1\n");

  pthread_exit(0);

  }

  /*

  * thread2() will be execute by thread2, after pthread_create()

  * it will set g_Flag = 2;

  */

  void* thread2(void* arg)

  {

  printf("enter thread2\n");

  printf("this is thread2, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());

  g_Flag = 2;

  printf("this is thread1, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());

  printf("leave thread2\n");

  pthread_exit(0);

  }

  This completes 1), 2), 3) these three requirements. Compilation was executed the following results:

  netsky@ubuntu:~/workspace/pthead_test$ gcc -lpthread test.c

  If used in the program to pthread library function, in addition to #include, at compile time as well as add -lpthread options.

  netsky@ubuntu:~/workspace/pthead_test$ ./a.out

  enter main

  enter thread2

  this is thread2, g_Flag: 0, thread id is 3079588720

  this is thread1, g_Flag: 2, thread id is 3079588720

  leave thread2

  leave main

  enter thread1

  this is thread1, g_Flag: 2, thread id is 3071196016

  this is thread1, g_Flag: 1, thread id is 3071196016

  leave thread1

  However, operating results are not necessarily the above, there may be:

  netsky@ubuntu:~/workspace/pthead_test$ ./a.out

  enter main

  leave main

  enter thread1

  this is thread1, g_Flag: 0, thread id is 3069176688

  this is thread1, g_Flag: 1, thread id is 3069176688

  leave thread1

  or:

  netsky@ubuntu:~/workspace/pthead_test$ ./a.out

  enter main

  leave main

  and many more. It is also well understood because, depending on when the main thread main function terminates, the thread thread1, thread2 is able to come urgently carry out their functions. It is also multi-threaded programming issues to consider, because there may be a thread will affect all other threads whole process! If we are in front of the main function exits, sleep () for some time, it can guarantee thread1, thread2 time to execute.

  

bloodsucking bat

 

  Attention: I am sure you have noticed, we are in the thread function thread1 (), thread2 () are called pthread_exit before executed. If I call exit () or is the return will happen then? Try it yourself!

  the pthread_exit () for a thread exits, the return value can be specified, so that other threads the thread function to obtain a return value by pthread_join ().

  return is a function return, function return only thread, the thread will exit.

  exit is the process of withdrawal, if the calling exit in the thread function, all functions are in the process of exit! "4) line program 1 need to exit after the thread 2 to exit" Point 4 is also very easy to solve, to exit the function thread1 of before calling pthread_join OK.

  Mutual exclusion between 4 threads

  The code above seems to be a good solution to the problem of the previous four demands, it is not true! Because g_Flag is a global variable, thread thread1 and thread2 can simultaneously manipulate it, it needs to be locked to protect, thread1 and thread2 exclusive access to the job. Here we describe how lock protection - mutex.

  Mutex:

  Use mutex (mutual exclusion) thread execution order. Often, the mutex by ensuring that only one thread is executing a critical section of code to synchronize multiple threads. Mutex can also protect single-threaded code. Correlation function operation mutex as follows:

  #include

  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

  Pthread_mutex_lock need to lock before the operation of critical resources, after completing the operation pthread_mutex_unlock then unlocked. And in that before declaring a variable of type pthread_mutex_t, as the first two parameters of the function. Specific code see Section 5.

  5 synchronization between threads

  Point 5 - exits the main thread is detected g_Flag from 1 to 2, or from 2 to 1 time. You need to use thread synchronization technology! Thread synchronization required condition variable.

  Condition variables:

  Use condition variables to atomically block threads can, until a certain condition is true so far. Always use condition variables together with a mutex. Test conditions is carried out under the protection of a mutex (mutual exclusion) of.

  If the condition is false, the thread is usually blocked on the condition variable and atomically releases the mutex wait to changing conditions. If another thread changes the condition, the thread may signal the associated condition variable, so that one or more threads wait to do the following:

  wake

  Acquire the mutex again

  Re-evaluate conditions

  In the following cases, the condition variable can be used to synchronize threads among processes:

  A thread is allocated in memory that can be written in

  Memory shared by cooperating processes

  "Conditions variables can atomically block a thread until a certain condition is true so far." Is used to point 5, the main function of blocking the main thread to wait g_Flag from 1 to 2, or from 2 to 1. Condition variable correlation function as follows:

  #include

  int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr);

  int pthread_cond_signal(pthread_cond_t *cptr);

  //Both return: 0 if OK, positive Exxx value on error

  pthread_cond_wait waiting for a particular condition is true, pthread_cond_signal blocked thread used to notify a particular condition is true. Before the caller pthread_cond_t two functions need to declare a variable of type parameters for these two functions.

  Why Always use condition variables together with a mutex, test conditions is carried out under the protection of a mutex (mutual exclusion) it? Because "a feature conditions" are usually shared between multiple threads of a variable. Mutex and allow this variable may be set to detect different threads.

  Usually, pthread_cond_wait just waiting for a condition variable wake of a thread. If you need to wake up all threads waiting for a condition variable, call:

  int pthread_cond_broadcast (pthread_cond_t * cptr);

  The following default, blocked thread will wait, you know that one variable is true. If you want to set the maximum blocking time can call:

  int pthread_cond_timedwait (pthread_cond_t * cptr, pthread_mutex_t *mptr, const struct timespec *abstime);

  If the time is up, no condition variable is true, still returns, the return value ETIME.

  6, the final code questions

  By the previous introduction, we can easily write code as follows:

  /*

  ? Are familiar with the POSIX multithreaded programming techniques such as familiar to program the following functions:

  1) there is a global variable of type int g_Flag initial value of 0;

  2) In the main thread 1, said the start, print "this is thread1", and g_Flag set to 1

  3) in the main line, said start thread 2, print "this is thread2", and g_Flag to 2

  4) line 1 need to exit the program after the thread exits 2

  5) detection of the primary thread exits g_Flag from 1 to 2, or from 2 to 1 time

  */

  #include

  #include

  #include

  #include

  #include

  typedef void* (*fun)(void*);

  int g_Flag=0;

  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

  static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

  void* thread1(void*);

  void* thread2(void*);

  /*

  * when program is started, a single thread is created, called the initial thread or main thread.

  * Additional threads are created by pthread_create.

  * So we just need to create two thread in main().

  */

  int main(int argc, char** argv)

  {

  printf("enter main\n");

  pthread_t tid1, tid2;

  int rc1=0, rc2=0;

  rc2 = pthread_create(&tid2, NULL, thread2, NULL);

  if(rc2 != 0)

  printf("%s: %d\n",__func__, strerror(rc2));

  rc1 = pthread_create(&tid1, NULL, thread1, &tid2);

  if(rc1 != 0)

  printf("%s: %d\n",__func__, strerror(rc1));

  pthread_cond_wait(&cond, &mutex);

  printf("leave main\n");

  exit(0);

  }

  /*

  * thread1() will be execute by thread1, after pthread_create()

  * it will set g_Flag = 1;

  */

  void* thread1(void* arg)

  {

  printf("enter thread1\n");

  printf("this is thread1, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());

  pthread_mutex_lock(&mutex);

  if(g_Flag == 2)

  pthread_cond_signal(&cond);

  g_Flag = 1;

  printf("this is thread1, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());

  pthread_mutex_unlock(&mutex);

  pthread_join(*(pthread_t*)arg, NULL);

  printf("leave thread1\n");

  pthread_exit(0);

  }

  /*

  * thread2() will be execute by thread2, after pthread_create()

  * it will set g_Flag = 2;

  */

  void* thread2(void* arg)

  {

  printf("enter thread2\n");

  printf("this is thread2, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());

  pthread_mutex_lock(&mutex);

  if(g_Flag == 1)

  pthread_cond_signal(&cond);

  g_Flag = 2;

  printf("this is thread2, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());

  pthread_mutex_unlock(&mutex);

  printf("leave thread2\n");

  pthread_exit(0);

  }

  The results can be compiled to run to meet the requirements!

  linux foundation

  http://www.makeru.com.cn/course/details/2058?s=45051

  Quick Start linux

  http://www.makeru.com.cn/live/1758_310.html?s=45051

  linux multi-threaded programming

  http://www.makeru.com.cn/course/details/1937?s=45051

  Application of linear and circular list table

  http://www.makeru.com.cn/course/details/1902?s=45051

  High concurrent programming of thread pool

  http://www.makeru.com.cn/live/5413_1935.html?s=45051

Guess you like

Origin www.cnblogs.com/923327iu/p/12403148.html