Description: What are the threads and what are the advantages of threading
Threads are often referred to as lightweight processes under UNIX systems, and threads are not processes, but can be seen as cousins of UNIX processes, and multiple threads in the same process will share all system resources in the process, such as virtual address space, file descriptors, signal processing, and so on . But multiple threads in the same process have their own calling stack (call stack), their own register environment (register context), their own thread-local storage (thread-local storage). A process can have many threads, and each thread performs different tasks in parallel.
Threads can improve the performance of applications that handle blocking situations such as file I/O or socket I/O in multicore environments. In UNIX systems, a process contains many things, including executable programs and a whole host of resources such as the file descriptor address space. In many cases, there is a need to exchange data between different code that completes the related task. If the multi-process approach, then the communication needs in the user space and kernel space for frequent switching, the overhead is very large. But if you use multithreading, because you can use shared global variables, communication between threads (data exchange) becomes very efficient.
Hello World (thread creation, end, wait) create thread pthread_create
The thread-creation function consists of four variables, respectively: 1. A thread variable name that is created by the thread's identity 2. The property pointer of the thread, which defaults to NULL to 3. Program code 4 for the thread being created. Program code parameters for example:-pthread_t thrd1; -pthread_attr_t attr;-void thread_function (void argument); -Char *some_argument;
pthread_create(&thrd1, NULL, (void *)&thread_function, (void *) &some_argument);
End Thread Pthread_exit
Thread End Invocation instance: pthread_exit(void *retval);
//retval used to hold the exit state of the thread end
Thread waits for Pthread_join
After the pthread_create call succeeds, the new thread and the old thread who executes first, who executes after the user is unaware, this piece depends on the operating system on the thread's dispatch, if we need to wait for the specified thread to end, need to use the Pthread_join function, This function is actually similar to waitpid in multi-process programming. For example, the following assumes that a thread calls Pthread_join to attempt to manipulate the B thread, which blocks the a thread until the B thread exits, and a thread collects the return code of the B thread after the B thread exits. The function consists of two parameters:
- pthread_t th//th is the identity of the thread to wait for the end
- void **thread_return//pointer Thread_return points to the location where the terminating thread's return status is stored.
Invoke instance:pthread_join(thrd1, NULL);
Example1:
1/************************************************************************* 2 > File name:thread_hello_world.c 3 > Author:couldtt (fyby) 4 > Mail: [email protected] 5 > Created time:2013 year December 14 Saturday 11:48 5 0 SEC 6 ************************************************************************/7 8 #include <stdio.h> 9 #include <stdlib.h>10 #include <pthread.h>11 (void *ptr), print_message_function int main () TMP1, tmp2;17 void *retval;18 pthread_t thread1, thread2;19 char *message1 = "Thread1"; char *message2 = "Thread2"; int ret_thrd1, ret_thrd2;23 ret_thrd1 = Pthread_create (&thread1, NULL, (void *) &print_ Message_function, (void *) message1); ret_thrd2 = Pthread_create (&thread2, NULL, (void *) &print_message_func tion, (void *) message2); 26 27//thread created successfully, returned 0, failed to return failure number if (ret_thrd1! = 0) {printf ("Thread 1 creation failed \ n"); 30 } else {printf("Thread 1 creation succeeded \ n"),}33 if (ret_thrd2! = 0) {"2" ("Thread of creation failed \ n"), or else {Notoginseng printf ("Thread 2 gen 38}39 40//The return value of the Pthread_join is successfully 041 TMP1 = Pthread_join (Thread1, &retval), and printf ("Thread1 return value (retval) is%d\n ", (int.) retval); printf (" Thread1 return value (TMP) is%d\n ", TMP1); if (tmp1! = 0 {"Cannot join with thread1\n"),}47 printf ("Thread1 end\n"), TMP2 = pthread_join (th Read1, &retval); printf ("Thread2 return value (retval) is%d\n", (int) retval), and printf ("Thread2 return value (TMP) is%d\n ", TMP1); if (tmp2! = 0) {printf (" Cannot join with thread2\n "), and}55 printf (" Thread 2 end\n "),}58 print_message_function (void *ptr) {$ int i = 0;61 for (i; i<5; i++) {62 printf ("%s:%d\n", (char *) ptr, i); 63}64}
Compile
gcc thread_hello_world.c -otest -lpthread
Be sure to add -lpthread
, otherwise will error, because the source code refers to the pthread.h, so when the GCC link, you must find the binary implementation code of these libraries.
Run results
Results analysis: 1. This program I run two times, you can see, two times the result is not the same, thus indicating that the new thread and the old thread who first executed, who after the execution of the user is not aware of, this piece depends on the operation of the operating system on the thread scheduling . 2. In addition, we see that in the Thread2 join result error, print out cannot join with thread2
actually this is a small error, because, I pthread_join in the th is thread1, in the results above, Thread1 is already over, So we wait again for thread1 to end up with an error that cannot be taken to the state. 3.pthread_join (Thread1, &retval) did wait for the end of the Thread1, and we saw that print_message_function
after the function had been cycled 5 times, the Thread1 end was printed out
This is a very simple example, Hello world level, just to demonstrate the use of Linux under C Multithreading, in practical applications, because multiple threads tend to access shared resources (typically access the same global variable), so there is a competitive relationship between the counties, This requires synchronizing multiple threads to protect the data they access.
Multi-threaded synchronization and Mutual exclusion method: Lock
- Initialize the lock to unlock state in the main thread
- pthread_mutex_t Mutex;
- Pthread_mutex_init (&mutex, NULL);
- Initialize lock to unlock state at compile time
- Lock initialization pthread_mutex_t mutex = Pthread_mutex_initializer;
- Lock operation and unlock operation when accessing an object
- Locking Pthread_mutex_lock (&mutex)
- Release lock Pthread_mutex_unlock (&mutex)
No lock, no data synchronization
Let's look at a program that accesses the same piece of data without locking and multiple threads.
1/************************************************************************* 2 > File name:no_mutex.c 3 > AUTHOR:COULDTT (fyby) 4 > Mail: [email protected] 5 > Created time:2013 year December 15 Sunday 17:52 24 seconds 6 ****** /7 8 #include <stdio.h> 9 #include < stdlib.h>10 #include <pthread.h>11 int sharedi = 0;13 void Increse_num (void), + int main () {+ int ret;1 7 pthread_t Thrd1, Thrd2, thrd3;18 ret = pthread_create (&thrd1, NULL, (void *) increse_num, NULL); RET = Pthread_create (&thrd2, NULL, (void *) increse_num, null); ret = pthread_create (&thrd3, NULL, (void *) Incre Se_num, NULL), Pthread_join (Thrd1, null), Pthread_join (Thrd2, null), Pthread_join (thrd3, NULL); 26 27 printf ("Sharedi =%d\n", Sharedi); return 0;30 to}32 void Increse_num (void) {long i,tmp;35 for (i=0; i<=100000; i++) {36 TMP = sharedi;37 TMP = tmp + 1;38 Sharedi = tmp;39}40}
Compile
gcc no_mutex.c -onomutex -lpthread
Run analysis
As we know, we no_mutex the results of each operation are inconsistent, and the result of the operation is not in line with our expectations, there have been incorrect results. The reason is that three threads compete for access to global variable Sharedi, and none are synchronized accordingly.
For example, when a thread thrd1 access to Sharedi, the value of Sharedi is 1000, and then the thread thrd1 adds the Sharedi value to 1001, but when the thread Thrd2 takes Sharedi, the Sharedi value is 1000. At this time the thread thrd2 the value of the Sharedi to 1, making it 1001, but at this point, the value of Sharedi has been added to the thread Thrd1 1001, however, thrd2 do not know, so the value of Sharedi is assigned to 1001, This results in errors.
In this way, we need a mutually exclusive mechanism to protect the Sharedi variable so that only one thread can access the variable at the same time, so that its value can guarantee the correct change.
Lock, data synchronization
By locking, the Sharedi variable is guaranteed to change, and only one thread can fetch it, and other threads cannot access it while the thread is working on it.
1/************************************************************************* 2 > File name:mutex.c 3 > Au THOR:COULDTT (fyby) 4 > Mail: [email protected] 5 > Created time:2013 year December 15 Sunday 17:52 24 seconds 6 ******* /7 8 #include <stdio.h> 9 #include < stdlib.h>10 #include <pthread.h>11 int sharedi = 0;13 void Increse_num (void); pthread_mutex_t mutex = PTH read_mutex_initializer;16 int main () {ret;19 int. pthread_t thrd1, THRD2, thrd3;20 ret = pthread_create (&thrd1, NULL, (void *) increse_num, null); ret = pthread_create (&thrd2, NULL, (void *) increse_num, NULL); 23 ret = pthread_create (&thrd3, NULL, (void *) increse_num, NULL); Pthread_join (thrd1, null); Pthread_j Oin (THRD2, null); Pthread_join (thrd3, null); printf ("Sharedi =%d\n", Sharedi); return 0;32 33}34 void Increse_num (void) {36 Long i,tmp;37 for (i=0; i<=100000; i++) {38 */locking */39 if (Pthread_mutex_lock (&mutex)! = 0) {40 Perror ("Pthread_mutex_lock"); exit (exit_failure),}43 tmp = sharedi;44 tmp = TMP + 1;45 Sharedi = tmp;46/* Ching */47 if (Pthread_mutex_unlock (&mutex)! = 0) {Perro R ("Pthread_mutex_unlock"); Exit_failure exit; 50}51}52}
Results analysis
This time, our results are correct, and the locks are effective in protecting our data security. However:
Lock protection is not our shared variable (or shared memory), for shared memory, the user cannot directly protect it, because that is the physical memory, can not prevent the code access of other programs. In fact, the lock is protecting critical areas, in this case, because all threads follow a rule, which is to enter the key area of the money 同一把
lock, in the exit key area money release 同一把
lock
We can see from the above running results, locking is to bring additional overhead, lock code its running speed, significantly slower than not to lock, so, in the use of locks, to be reasonable, in the case of no need to protect the critical areas, we do not add to the superfluous, lock it
Mode two: Signal volume
The lock has a very obvious drawback, and that is it 只有两种状态
: locking and not locking.
The semaphore is essentially a non-negative integer counter that is also used to control access to public resources. When the public resources increase, call the semaphore increment function sem_post () to increase it, and when the public resources are reduced, call the function sem_wait () to reduce the semaphore. In fact, we can treat the lock as a 0-1 semaphore.
They are /usr/include/semaphore.h
defined in, the semaphore data structure is sem_t, essentially, it is a long integer
Related functions
Before using semaphore, we need to first introduce the header file#include <semaphore.h>
- To initialize the semaphore:
int sem_init(sem_t *sem, int pshared, unsigned int value);
- Successful return 0, failure return-1
- Parameters
- SEM: A pointer to a semaphore structure
- Pshared: When not 0, the semaphore is shared between processes, otherwise it can only be shared for all threads of the current process
- Value: The initial value of the semaphore
- The signal volume minus 1 operation, when sem=0 the function will block
int sem_wait(sem_t *sem);
- Successful return 0, failure return-1
- Parameters
- SEM: A pointer to the semaphore
- Signal Volume plus 1 operation
int sem_post(sem_t *sem);
- Parameter and return as above
- Destroy Signal Volume
int sem_destroy(sem_t *sem);
- Parameter and return as above
code example
1/************************************************************************* 2 > File name:sem.c 3 > Autho R:COULDTT (fyby) 4 > Mail: [email protected] 5 > Created time:2013 year December 15 Sunday 19:25 08 seconds 6 ********** /7 8 #include <stdio.h> 9 #include <unistd.h >10 #include <pthread.h>11 #include <semaphore.h>12 #define MAXSIZE 1014 int stack[maxsize];16 int SI Ze = 0;17 sem_t sem;18 19//producer void Provide_data (void) {+ int i;22 for (i=0; i< MAXSIZE; i++) {23 Stack[i] = i;24 sem_post (&SEM); For Semaphore plus 125}26}27 28//consumer void Handle_data (void) {int i;31 while ((i = size++) < MAXSIZE) {32 Sem_wait (&sem); printf ("Multiplication:%d X%d =%d\n", Stack[i], stack[i], stack[i]*stack[i]); sleep (1); 35 }36}37 int main (void) {0 pthread_t provider, handler;41 sem_init (&sem,, 0);/semaphore initialization of pthread_create (&provider, NULL, (void *) handle_data, NULL), pthread_create (&handler, NULL, (VO ID *) provide_data, NULL); Pthread_join (provider, null); Pthread_join (handler, null); Sem_destroy (&se m); Destroy signal volume, return 0;50}
Operation Result:
Because the semaphore mechanism exists, so when the code is in Handle_data, if Sem_wait (&sem), the SEM is 0, then the code is blocked on the sem_wait, thus preventing the entire program from crashing by accessing the wrong index in the stack.
Resources
- [1] http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
- [2] "C language application programming under Linux" (Beijing University of Aeronautics and Astronautics Press)
- [3] Getting started with POSIX thread
Reproduced Step by Step:linux C multithreaded Programming primer (Basic API and multi-threaded synchronization and mutual exclusion)