Linux multithreading
1. Thread Overview
A thread is a basic scheduling unit in a process, also known as a lightweight process. Threads are concurrent multi-path execution paths in the shared memory space. They share the resources of a process, such as file descriptions and signal processing. Therefore, context switching overhead is greatly reduced. A process can have multiple threads.
There are multiple thread control tables and stack registers, but one user address space is shared.
2. Thread implementation
Thread creation pthread_create ()
Required header file # include <pthread. h>
Function prototype int pthread_create (pthread_t * thread, pthread_attr_t * attr,
Void * (* start_routine) (void *), void * arg ))
Thread: Specifies the thread ID.
Attr: thread attribute settings
Start_routine: the starting address of the thread function.
Arg: parameters passed to start_routine
Function return value success: 0 error:-1
The thread exits pthread_exit ();
Required header file # include <pthread. h>
Function prototype void pthread_exit (void * retval)
Function input value retval: the return value of the pthread_exit () caller's thread, which can be retrieved and obtained by other functions such as pthread_join.
Wait for the thread to exit and release the resource pthread_join ()
Required header file # include <pthread. h>
Function prototype int pthread_join (pthread_t th, void ** thread_return ))
Function input value
Th: ID of the waiting thread
Thread_return: User-Defined pointer, used to store the return value of the waiting thread (not NULL)
Function return value success: 0 error:-1
Code example
1. # include <pthread. h>
2. # include <stdio. h>
3. # include <errno. h>
4.
5./* thread 1 */
6. void thread1 ()
7 .{
8. int I = 0;
9.
10. while (1)
11 .{
12. printf ("thread1: % d \ n", I );
13. if (I> 3)
14. pthread_exit (0 );
15. I ++;
16. sleep (1 );
17 .}
18 .}
19.
20./* thread 2 */
21. void thread2 ()
22 .{
23. int I = 0;
24.
25. while (1)
26 .{
27. printf ("thread2: % d \ n", I );
28. if (I> 5)
29. pthread_exit (0 );
30. I ++;
31. sleep (1 );
32 .}
33 .}
34.
35. int main ()
36 .{
37. pthread_t t1, t2;
38.
39./* Create thread */
40. pthread_create (& t1, NULL, (void *) thread1, NULL );
41. pthread_create (& t2, NULL, (void *) thread2, NULL );
42./* Wait for the thread to exit */
43. pthread_join (t1, NULL );
44. pthread_join (t2, NULL );
45. return 0;
46 .}
3. Synchronization and mutex
<1> mutex lock
The operations of mutex lock mainly include the following steps.
• Mutex lock initialization: pthread_mutex_init
• Mutex lock: pthread_mutex_lock
• Mutex lock: pthread_mutex_trylock
• Mutex lock: pthread_mutex_unlock
• Remove mutex: pthread_mutex_destroy
1. # include <pthread. h>
2. # include <stdio. h>
3. # include <errno. h>
4.
5. int I = 0;/* shared variable */
6. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/* mutex lock */
7.
8. void thread1 ()
9 .{
10. int ret;
11. while (1)
12 .{
13.
14.
15. ret = pthread_mutex_trylock (& mutex);/* determine the lock */
16.
17. if (ret! = EBUSY)
18 .{
19. pthread_mutex_lock (& mutex);/* Lock */
20. printf ("This is thread1: % d \ n", I );
21. I ++;
22. pthread_mutex_unlock (& mutex);/* unlock */
23 .}
24. sleep (1 );
25 .}
26 .}
27.
28. void thread2 ()
29. {int ret;
30. while (1)
31 .{
32.
33. ret = pthread_mutex_trylock (& mutex );
34. if (ret! = EBUSY)
35 .{
36. pthread_mutex_lock (& mutex );
37. printf ("This is thread2: % d \ n", I );
38. I ++;
39. pthread_mutex_unlock (& mutex );
40 .}
41. sleep (1 );
42 .}
43 .}
44. int main ()
45 .{
46. pthread_t t1, t2;
47. pthread_mutex_init (& mutex, NULL );
48. pthread_create (& t1, NULL, (void *) thread1, NULL );
49. pthread_create (& t2, NULL, (void *) thread2, NULL );
50.
51. pthread_join (t1, NULL );
52. pthread_join (t2, NULL );
53.
54. pthread_mutex_destroy (& mutex );
55. return 0;
56 .}
<2> semaphores
Two threads that are not synchronized
1. # include <pthread. h>
2. # include <stdio. h>
3. # include <errno. h>
4.
5. int I = 0;
6. void thread1 ()
7 .{
8.
9. while (1)
10 .{
11. printf ("This is thread1: % d \ n", I );
12. I ++;
13. sleep (1 );
14 .}
15 .}
16.
17.
18. void thread2 ()
19 .{
20.
21. while (1)
22 .{
23. printf ("This is thread2: % d \ n", I );
24. I ++;
25. sleep (1 );
26 .}
27 .}
28.
29. int main ()
30 .{
31. pthread_t t1, t2;
32.
33. pthread_create (& t1, NULL, (void *) thread1, NULL );
34. pthread_create (& t2, NULL, (void *) thread2, NULL );
35.
36. pthread_join (t1, NULL );
37. pthread_join (t2, NULL );
38.
39. return 0;
40 .}
The execution result is as follows:
This is thread1: 0
This is thread2: 1
This is thread2: 2
This is thread1: 3
This is thread2: 4
This is thread1: 4
This is thread2: 6
This is thread1: 7
......
We can see that:
1. Thread 2 does not have to be executed after thread 1. If thread 2 is required to be executed after thread 1, it is called synchronization.
2. Thread 1 and thread 2 may read shared variable I at the same time. If only one thread needs to read I at a time, it becomes mutually exclusive.
Use of semaphores
• Sem_init is used to create a semaphore and initialize its value.
• Sem_wait and sem_trywait are equivalent to P operations. Both of them can reduce the semaphore value by one. The difference between them is that if the semaphore is smaller than zero, sem_wait will block the process, and sem_trywait will return immediately.
• Sem_post is equivalent to the V operation. It adds the semaphore value and sends a signal to wake up the waiting process.
• Sem_getvalue is used to obtain the semaphore value.
• Sem_destroy is used to delete semaphores
Code
1. # include <pthread. h>
2. # include <stdio. h>
3. # include <errno. h>
4. # include <semaphore. h>
5.
6.
7. int I = 0;
8. sem_t sem1, sem2;
9.
10.
11. void thread1 ()
12 .{
13.
14. while (1)
15 .{
16. sem_wait (& sem1 );
17. printf ("This is thread1: % d \ n", I );
18. I ++;
19. sleep (3);/* thread 1 sleep for 3 s to observe that thread 2 will be executed after 3 s output */
20. sem_post (& sem2 );
21.
22 .}
23 .}
24.
25.
26. void thread2 ()
27 .{
28.
29. while (1)
30 .{
31. sem_wait (& sem2 );
32. printf ("This is thread2: % d \ n", I );
33. I ++;
34. sem_post (& sem1 );
35. sleep (1 );
36 .}
37 .}
38.
39. int main ()
40 .{
41. pthread_t t1, t2;
42.
43.
44.
45. sem_init (& sem1,);/* initialize semaphores sem1 */
46. sem_init (& sem2, 0, 0 );
47.
48. pthread_create (& t1, NULL, (void *) thread1, NULL );
49. pthread_create (& t2, NULL, (void *) thread2, NULL );
50.
51. pthread_join (t1, NULL );
52. pthread_join (t2, NULL );
53.
54. return 0;
55 .}
1. # include <pthread. h>
2. # include <stdio. h>
3. # include <errno. h>
4. # include <semaphore. h>
5.
6.
7. int I = 0;
8. sem_t sem;
9.
10.
11. void thread1 ()
12 .{
13.
14. while (1)
15 .{
16. sem_wait (& sem );
17. printf ("This is thread1: % d \ n", I );
18. I ++;
19. sleep (3);/* thread 1 sleep for 3 s to observe that thread 2 will be executed after 3 s output */
20. sem_post (& sem );
21.
22 .}
23 .}
24.
25.
26. void thread2 ()
27 .{
28.
29. while (1)
30 .{
31. sem_wait (& sem );
32. printf ("This is thread2: % d \ n", I );
33. I ++;
34. sem_post (& sem );
35. sleep (1 );
36 .}
37 .}
38.
39. int main ()
40 .{
41. pthread_t t1, t2;
42.
43.
44.
45. sem_init (& sem, 0, 1);/* initialize semaphores sem */
46.
47. pthread_create (& t1, NULL, (void *) thread1, NULL );
48. pthread_create (& t2, NULL, (void *) thread2, NULL );
49.
50. pthread_join (t1, NULL );
51. pthread_join (t2, NULL );
52.
53. return 0;
54 .}