074. 理解C语言中的多线程编程
C语言中的多线程编程允许程序同时执行多个任务,从而提高程序的效率和响应能力。多线程编程在现代软件开发中非常重要,尤其是在需要处理并发任务或提高性能的场景中。C语言标准库(C11)提供了线程支持,但更常见的多线程编程是通过POSIX线程(pthread)库实现的。
1. POSIX线程(pthread)
POSIX线程(pthread)是POSIX标准中定义的线程库,广泛用于类Unix系统(如Linux和macOS)。以下是一些基本的pthread函数及其用法。
1.1 创建线程
使用pthread_create
函数创建线程。
#include <stdio.h>
#include <pthread.h>
void* threadFunction(void* arg) {
printf("线程执行中...\n");
return NULL;
}
int main() {
pthread_t thread;
if (pthread_create(&thread, NULL, threadFunction, NULL) != 0) {
perror("线程创建失败");
return 1;
}
// 等待线程结束
if (pthread_join(thread, NULL) != 0) {
perror("线程等待失败");
return 1;
}
return 0;
}
1.2 线程同步
线程同步是多线程编程中的一个重要概念,用于防止数据竞争和保证线程安全。常见的同步机制包括互斥锁(mutex)、条件变量和读写锁。
1.2.1 互斥锁(Mutex)
互斥锁用于保护共享资源,确保同一时间只有一个线程可以访问该资源。
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int sharedVariable = 0;
void* incrementFunction(void* arg) {
for (int i = 0; i < 100000; i++) {
pthread_mutex_lock(&mutex);
sharedVariable++;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main() {
pthread_t thread1, thread2;
if (pthread_create(&thread1, NULL, incrementFunction, NULL) != 0) {
perror("线程创建失败");
return 1;
}
if (pthread_create(&thread2, NULL, incrementFunction, NULL) != 0) {
perror("线程创建失败");
return 1;
}
if (pthread_join(thread1, NULL) != 0) {
perror("线程等待失败");
return 1;
}
if (pthread_join(thread2, NULL) != 0) {
perror("线程等待失败");
return 1;
}
printf("共享变量的值: %d\n", sharedVariable);
return 0;
}
1.2.2 条件变量
条件变量用于线程间的同步,允许线程在某个条件满足时继续执行。
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int conditionMet = 0;
void* waitingFunction(void* arg) {
pthread_mutex_lock(&mutex);
while (!conditionMet) {
pthread_cond_wait(&cond, &mutex);
}
printf("条件已满足,线程继续执行...\n");
pthread_mutex_unlock(&mutex);
return NULL;
}
void* signalingFunction(void* arg) {
pthread_mutex_lock(&mutex);
conditionMet = 1;
pthread_cond_signal(&cond);
printf("条件已设置,通知等待线程...\n");
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_t thread1, thread2;
if (pthread_create(&thread1, NULL, waitingFunction, NULL) != 0) {
perror("线程创建失败");
return 1;
}
if (pthread_create(&thread2, NULL, signalingFunction, NULL) != 0) {
perror("线程创建失败");
return 1;
}
if (pthread_join(thread1, NULL) != 0) {
perror("线程等待失败");
return 1;
}
if (pthread_join(thread2, NULL) != 0) {
perror("线程等待失败");
return 1;
}
return 0;
}
2. C11线程支持
C11标准引入了线程支持,提供了<threads.h>
头文件,用于线程操作。
2.1 创建线程
#include <stdio.h>
#include <threads.h>
int threadFunction(void* arg) {
printf("线程执行中...\n");
return 0;
}
int main() {
thrd_t thread;
if (thrd_create(&thread, threadFunction, NULL) != thrd_success) {
perror("线程创建失败");
return 1;
}
// 等待线程结束
if (thrd_join(thread, NULL) != thrd_success) {
perror("线程等待失败");
return 1;
}
return 0;
}
2.2 线程同步
C11标准也提供了互斥锁和条件变量的支持。
2.2.1 互斥锁
#include <stdio.h>
#include <threads.h>
mtx_t mutex;
int sharedVariable = 0;
int incrementFunction(void* arg) {
for (int i = 0; i < 100000; i++) {
mtx_lock(&mutex);
sharedVariable++;
mtx_unlock(&mutex);
}
return 0;
}
int main() {
thrd_t thread1, thread2;
mtx_init(&mutex, mtx_plain);
if (thrd_create(&thread1, incrementFunction, NULL) != thrd_success) {
perror("线程创建失败");
return 1;
}
if (thrd_create(&thread2, incrementFunction, NULL) != thrd_success) {
perror("线程创建失败");
return 1;
}
if (thrd_join(thread1, NULL) != thrd_success) {
perror("线程等待失败");
return 1;
}
if (thrd_join(thread2, NULL) != thrd_success) {
perror("线程等待失败");
return 1;
}
printf("共享变量的值: %d\n", sharedVariable);
mtx_destroy(&mutex);
return 0;
}
3. 注意事项
-
线程安全:使用互斥锁或其他同步机制保护共享资源,避免数据竞争。
-
线程同步:使用条件变量或信号量来协调线程间的执行顺序。
-
线程销毁:确保线程结束后释放相关资源,避免内存泄漏。
-
线程数量:创建过多的线程可能会导致系统资源耗尽,合理控制线程数量。
-
线程库的选择:POSIX线程(pthread)是类Unix系统中广泛使用的线程库,功能丰富。C11线程支持是C语言标准的一部分,但支持的编译器可能较少。
4. 总结
多线程编程是C语言中一个强大的工具,可以显著提高程序的性能和响应能力。通过使用POSIX线程(pthread)或C11线程支持,可以实现线程的创建、同步和销毁。合理使用线程同步机制,如互斥锁和条件变量,可以避免数据竞争和线程安全问题。在实际开发中,应根据具体需求选择合适的线程库和同步机制。
视频讲解
BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)