C多线程编程之mutex
很多刚开始学习编程的新人可能觉得多线程,锁机制,共享资源不好理解。其实这是正常的,学校期间非计算机专业的学生很少能够接触到多线程编程的教学内容。但是不要担心,单线程编程和多线程之间,资源与共享资源之间只有一层窗户纸,并没有那么晦涩难懂。
笔者会从mutex入手,使用多线程编程,锁,共享资源写一个demo代码,通过实例来说明概念。
1 #include <pthread.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 #define NUM_THREADS 5
6 #define NUM_INCREMENTS 1000000
7
8 // Shared resource
9 int counter = 0;
10
11 // Mutex to protect the shared resource
12 pthread_mutex_t counter_mutex;
13
14 void* increment_counter(void* arg) {
15 for (int i = 0; i < NUM_INCREMENTS; i++) {
16 // Lock the mutex before accessing the shared resource
17 pthread_mutex_lock(&counter_mutex);
18
19 // Increment the counter
20 counter++;
21
22 // Unlock the mutex after accessing the shared resource
23 pthread_mutex_unlock(&counter_mutex);
24 }
25 return NULL;
26 }
27
28 int main() {
29 pthread_t threads[NUM_THREADS];
30 int thread_ids[NUM_THREADS];
31
32 // Initialize the mutex
33 if (pthread_mutex_init(&counter_mutex, NULL) != 0) {
34 perror("Failed to initialize mutex");
35 exit(EXIT_FAILURE);
36 }
37
38 // Create threads
39 for (int i = 0; i < NUM_THREADS; i++) {
40 thread_ids[i] = i;
41 if (pthread_create(&threads[i], NULL, increment_counter, &thread_ids[i]) != 0) {
42 perror("Failed to create thread");
43 exit(EXIT_FAILURE);
44 }
45 }
46
47 // Wait for all threads to complete
48 for (int i = 0; i < NUM_THREADS; i++) {
49 if (pthread_join(threads[i], NULL) != 0) {
50 perror("Failed to join thread");
51 exit(EXIT_FAILURE);
52 }
53 }
54
55 // Destroy the mutex
56 pthread_mutex_destroy(&counter_mutex);
57
58 // Print the final value of the counter
59 printf("Final counter value: %d\n", counter);
60
61 return 0;
62 }
输出:
Final counter value: 5000000
介绍头文件pthread.h
在C语言的多线程编程中,POSIX线程(pthread)库是一个强大的工具,提供了丰富的功能用于线程管理和同步。pthread
库的头文件是pthread.h
,它包含了创建和管理线程以及线程间同步的所有函数和数据类型定义。
pthread.h 头文件
pthread.h
头文件是POSIX线程库的入口,包含了所有相关的定义和声明。以下是一些主要的内容:
-
线程管理函数:
pthread_create
: 创建一个新线程。pthread_join
: 等待指定线程终止。pthread_exit
: 终止调用线程。pthread_cancel
: 请求取消一个线程。pthread_detach
: 将线程设置为分离状态。
-
线程同步函数:
pthread_mutex_init
: 初始化互斥锁(mutex)。pthread_mutex_destroy
: 销毁互斥锁。pthread_mutex_lock
: 锁定互斥锁。pthread_mutex_unlock
: 解锁互斥锁。pthread_cond_init
: 初始化条件变量。pthread_cond_destroy
: 销毁条件变量。pthread_cond_wait
: 等待条件变量。pthread_cond_signal
: 发出条件变量信号。pthread_cond_broadcast
: 广播条件变量信号。
-
其他数据类型和宏:
pthread_t
: 线程标识符的数据类型。pthread_attr_t
: 线程属性对象的数据类型。pthread_mutex_t
: 互斥锁的数据类型。pthread_mutexattr_t
: 互斥锁属性对象的数据类型。pthread_cond_t
: 条件变量的数据类型。pthread_condattr_t
: 条件变量属性对象的数据类型。PTHREAD_MUTEX_INITIALIZER
: 静态初始化互斥锁的宏。PTHREAD_COND_INITIALIZER
: 静态初始化条件变量的宏。
示例代码:基本线程和互斥锁使用
以下是一个使用pthread.h
头文件进行多线程编程的简单示例,展示了如何创建线程并使用互斥锁同步对共享资源的访问。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 5
#define NUM_INCREMENTS 1000000
// 共享资源
int counter = 0;
// 互斥锁保护共享资源
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
void* increment_counter(void* arg) {
for (int i = 0; i < NUM_INCREMENTS; i++) {
// 在访问共享资源前锁定互斥锁
pthread_mutex_lock(&counter_mutex);
// 增加计数器
counter++;
// 访问共享资源后解锁互斥锁
pthread_mutex_unlock(&counter_mutex);
}
return NULL;
}
int main() {
pthread_t threads[NUM_THREADS];
// 创建线程
for (int i = 0; i < NUM_THREADS; i++) {
if (pthread_create(&threads[i], NULL, increment_counter, NULL) != 0) {
perror("Failed to create thread");
exit(EXIT_FAILURE);
}
}
// 等待所有线程完成
for (int i = 0; i < NUM_THREADS; i++) {
if (pthread_join(threads[i], NULL) != 0) {
perror("Failed to join thread");
exit(EXIT_FAILURE);
}
}
// 输出最终计数器的值
printf("Final counter value: %d\n", counter);
// 销毁互斥锁
pthread_mutex_destroy(&counter_mutex);
return 0;
}
说明
-
线程创建:
- 使用
pthread_create
函数创建新线程,每个线程运行increment_counter
函数。
- 使用
-
互斥锁:
- 互斥锁
counter_mutex
在共享资源counter
上提供保护,防止多个线程同时访问该资源。 pthread_mutex_lock
和pthread_mutex_unlock
分别用于锁定和解锁互斥锁,确保只有一个线程在任意时刻访问共享资源。 当线程试图解锁counter_mutex时,如果有其他线程已经解锁了counter_mutex,那么当前线程会被操作系统挂起,当其他线程解锁了counter_mutex,操作系统会在将被挂起的线程激活来继续执行。
- 互斥锁
-
线程同步:
- 使用
pthread_join
等待所有线程完成,确保在主线程结束前所有子线程都已完成。
- 使用
-
资源清理:
- 在使用完互斥锁后,使用
pthread_mutex_destroy
销毁互斥锁,释放相关资源。
- 在使用完互斥锁后,使用
总结
通过包含pthread.h
头文件,可以使用POSIX线程库提供的各种功能来实现多线程程序。互斥锁是一个重要的同步工具,用于确保多线程环境下对共享资源的安全访问。理解和正确使用这些功能是编写高效、安全的多线程程序的关键。