087. 理解C语言中的并发编程
并发编程是指同时执行多个任务,这些任务可以是线程、进程或协程。在C语言中,并发编程通常通过多线程或多进程实现。并发编程可以显著提高程序的性能,尤其是在多核处理器上。然而,它也带来了同步和通信的挑战。
1. 并发编程的基本概念
1.1 线程(Threads)
线程是操作系统能够进行运算调度的最小单位。多个线程可以共享进程的资源,但每个线程有自己的执行栈和程序计数器。
1.2 进程(Processes)
进程是操作系统分配资源的基本单位。每个进程有自己的地址空间、内存、数据栈等。
1.3 协程(Coroutines)
协程是一种更轻量级的线程,通常由用户态管理,而不是由操作系统内核管理。C语言标准库中没有直接支持协程,但可以通过库(如libtask
)实现。
2. 多线程编程
在C语言中,多线程编程通常通过POSIX线程(pthread)库实现。以下是一个简单的多线程示例。
示例代码:多线程
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* threadFunction(void* arg) {
int* data = (int*)arg;
printf("线程 %d 执行中...\n", *data);
return NULL;
}
int main() {
pthread_t threads[5];
int thread_ids[5];
for (int i = 0; i < 5; i++) {
thread_ids[i] = i;
if (pthread_create(&threads[i], NULL, threadFunction, &thread_ids[i]) != 0) {
perror("线程创建失败");
return 1;
}
}
for (int i = 0; i < 5; i++) {
if (pthread_join(threads[i], NULL) != 0) {
perror("线程等待失败");
return 1;
}
}
return 0;
}
示例运行
输入:
无输入
输出:
线程 0 执行中...
线程 1 执行中...
线程 2 执行中...
线程 3 执行中...
线程 4 执行中...
3. 多进程编程
在C语言中,多进程编程通常通过fork
函数实现。以下是一个简单的多进程示例。
示例代码:多进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void processFunction(int pid) {
printf("进程 %d 执行中...\n", pid);
}
int main() {
pid_t pids[5];
for (int i = 0; i < 5; i++) {
pids[i] = fork();
if (pids[i] < 0) {
perror("进程创建失败");
return 1;
} else if (pids[i] == 0) {
// 子进程
processFunction(i);
exit(0);
}
}
for (int i = 0; i < 5; i++) {
wait(NULL); // 等待子进程结束
}
return 0;
}
示例运行
输入:
无输入
输出:
进程 0 执行中...
进程 1 执行中...
进程 2 执行中...
进程 3 执行中...
进程 4 执行中...
4. 线程同步
在多线程编程中,同步是一个关键问题。C语言提供了多种同步机制,如互斥锁(mutex)、条件变量和读写锁。
示例代码:互斥锁
#include <stdio.h>
#include <stdlib.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 threads[2];
for (int i = 0; i < 2; i++) {
if (pthread_create(&threads[i], NULL, incrementFunction, NULL) != 0) {
perror("线程创建失败");
return 1;
}
}
for (int i = 0; i < 2; i++) {
if (pthread_join(threads[i], NULL) != 0) {
perror("线程等待失败");
return 1;
}
}
printf("共享变量的值: %d\n", sharedVariable);
return 0;
}
示例运行
输入:
无输入
输出:
共享变量的值: 200000
5. 注意事项
线程安全:
- 使用互斥锁或其他同步机制保护共享资源,避免数据竞争。
线程同步:
- 使用条件变量或信号量来协调线程间的执行顺序。
线程销毁:
- 确保线程结束后释放相关资源,避免内存泄漏。
线程库的选择:
-
POSIX线程(pthread)是类Unix系统中广泛使用的线程库,功能丰富。
-
C11线程支持是C语言标准的一部分,但支持的编译器可能较少。
多进程与多线程的选择:
-
多进程适用于需要独立地址空间的场景,但进程间通信成本较高。
-
多线程适用于需要共享地址空间的场景,但线程同步和通信较为复杂。
6. 总结
通过使用多线程和多进程,可以在C语言中实现并发编程。多线程编程通过POSIX线程(pthread)库实现,而多进程编程通过fork
函数实现。合理使用线程同步机制,如互斥锁和条件变量,可以避免数据竞争和线程安全问题。在实际开发中,应根据具体需求选择合适的并发模型。
视频讲解
BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)