C 语言多线程与并发编程:提高程序执行效率
C 语言多线程与并发编程旨在利用多核 CPU 提升程序效率。内容涵盖线程与进程区别、并发并行概念、线程生命周期管理、同步机制(互斥锁、条件变量)、通信机制及常见并发问题(死锁、活锁)。提供生产者 - 消费者模型、数组求和等实战代码示例,指导开发者编写高效安全的并发程序。

C 语言多线程与并发编程旨在利用多核 CPU 提升程序效率。内容涵盖线程与进程区别、并发并行概念、线程生命周期管理、同步机制(互斥锁、条件变量)、通信机制及常见并发问题(死锁、活锁)。提供生产者 - 消费者模型、数组求和等实战代码示例,指导开发者编写高效安全的并发程序。


💡 多线程与并发编程是提高程序执行效率的重要手段!合理使用多线程可以充分利用多核 CPU 的优势,但也会引入线程同步和通信的问题。
| 特性 | 进程 | 线程 |
|---|---|---|
| 资源分配 | 独立的地址空间、内存、文件描述符等 | 共享进程的地址空间、内存、文件描述符等 |
| 通信方式 | 管道、消息队列、共享内存、套接字等 | 全局变量、局部变量、参数传递等 |
| 上下文切换成本 | 较高 | 较低 |
| 稳定性 | 进程崩溃不会影响其他进程 | 线程崩溃会影响整个进程 |
| 创建和销毁成本 | 较高 | 较低 |
代码示例 1:获取当前进程的 ID
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = getpid();
printf("当前进程的 ID:%d\n", pid);
return 0;
}
pthread_create 函数pthread_join 函数pthread_exit 函数pthread_cancel 函数功能:创建一个新线程
语法:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
参数说明:
thread:指向线程 ID 的指针attr:线程属性,通常为 NULLstart_routine:线程的入口函数arg:传递给线程入口函数的参数返回值:成功返回 0,失败返回错误码
代码示例 2:创建一个新线程
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void *thread_func(void *arg) {
int thread_id = *(int *)arg;
printf("线程%d正在执行!\n", thread_id);
sleep(1);
printf("线程%d执行完毕!\n", thread_id);
return NULL;
}
int main() {
pthread_t tid;
int thread_id = 1;
// 创建新线程
int ret = pthread_create(&tid, NULL, thread_func, &thread_id);
if (ret != 0) {
printf("线程创建失败!\n");
return 1;
}
printf("主线程正在执行!\n");
// 等待线程结束
ret = pthread_join(tid, NULL);
if (ret != 0) {
printf("线程等待失败!\n");
return 1;
}
printf("主线程执行完毕!\n");
return 0;
}
pthread_mutex 系列函数pthread_cond 系列函数pthread_rwlock 系列函数功能:保护共享数据,确保同一时间只有一个线程可以访问共享数据
代码示例 3:使用互斥锁保护共享数据
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int shared_data = 0;
pthread_mutex_t mutex;
void *thread_func(void *arg) {
int thread_id = *(int *)arg;
for (int i = 0; i < 10000; i++) {
pthread_mutex_lock(&mutex); // 加锁
shared_data++;
pthread_mutex_unlock(&mutex); // 解锁
}
printf("线程%d执行完毕!共享数据的值:%d\n", thread_id, shared_data);
return NULL;
}
int main() {
pthread_t tid1, tid2;
int thread_id1 = 1, thread_id2 = 2;
// 初始化互斥锁
int ret = pthread_mutex_init(&mutex, NULL);
if (ret != 0) {
printf("互斥锁初始化失败!\n");
return 1;
}
// 创建新线程
ret = pthread_create(&tid1, NULL, thread_func, &thread_id1);
if (ret != 0) {
printf("线程 1 创建失败!\n");
return 1;
}
ret = pthread_create(&tid2, NULL, thread_func, &thread_id2);
if (ret != 0) {
printf("线程 2 创建失败!\n");
return 1;
}
// 等待线程结束
ret = pthread_join(tid1, NULL);
if (ret != 0) {
printf("线程 1 等待失败!\n");
return 1;
}
ret = pthread_join(tid2, NULL);
if (ret != 0) {
printf("线程 2 等待失败!\n");
return 1;
}
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
printf("主线程执行完毕!共享数据的值:%d\n", shared_data);
return 0;
}
pthread_cond 系列函数sem 系列函数功能:用于线程之间的通信,等待某个条件的成立
代码示例 4:使用条件变量实现生产者 - 消费者模型
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
int count = 0;
pthread_mutex_t mutex;
pthread_cond_t cond_producer;
pthread_cond_t cond_consumer;
void *producer_func(void *arg) {
int thread_id = *(int *)arg;
for (int i = 0; i < 10; i++) {
pthread_mutex_lock(&mutex); // 加锁
// 等待缓冲区不满
while (count == BUFFER_SIZE) {
pthread_cond_wait(&cond_producer, &mutex);
}
// 生产数据
buffer[in] = i;
in = (in + 1) % BUFFER_SIZE;
count++;
printf("生产者%d生产了数据%d,缓冲区中有%d个数据\n", thread_id, i, count);
pthread_cond_signal(&cond_consumer); // 通知消费者
pthread_mutex_unlock(&mutex); // 解锁
sleep(1);
}
return NULL;
}
void *consumer_func(void *arg) {
int thread_id = *(int *)arg;
for (int i = 0; i < 10; i++) {
pthread_mutex_lock(&mutex); // 加锁
// 等待缓冲区不空
while (count == 0) {
pthread_cond_wait(&cond_consumer, &mutex);
}
// 消费数据
int data = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
printf("消费者%d消费了数据%d,缓冲区中有%d个数据\n", thread_id, data, count);
pthread_cond_signal(&cond_producer); // 通知生产者
pthread_mutex_unlock(&mutex); // 解锁
sleep(1);
}
return NULL;
}
int main() {
pthread_t producer_tid1, producer_tid2, consumer_tid1, consumer_tid2;
int producer_id1 = 1, producer_id2 = 2, consumer_id1 = 1, consumer_id2 = 2;
// 初始化互斥锁和条件变量
int ret = pthread_mutex_init(&mutex, NULL);
if (ret != 0) {
printf("互斥锁初始化失败!\n");
return 1;
}
ret = pthread_cond_init(&cond_producer, NULL);
if (ret != 0) {
printf("条件变量 1 初始化失败!\n");
return 1;
}
ret = pthread_cond_init(&cond_consumer, NULL);
if (ret != 0) {
printf("条件变量 2 初始化失败!\n");
return 1;
}
// 创建新线程
ret = pthread_create(&producer_tid1, NULL, producer_func, &producer_id1);
if (ret != 0) {
printf("生产者 1 创建失败!\n");
return 1;
}
ret = pthread_create(&producer_tid2, NULL, producer_func, &producer_id2);
if (ret != 0) {
printf("生产者 2 创建失败!\n");
return 1;
}
ret = pthread_create(&consumer_tid1, NULL, consumer_func, &consumer_id1);
if (ret != 0) {
printf("消费者 1 创建失败!\n");
return 1;
}
ret = pthread_create(&consumer_tid2, NULL, consumer_func, &consumer_id2);
if (ret != 0) {
printf("消费者 2 创建失败!\n");
return 1;
}
// 等待线程结束
ret = pthread_join(producer_tid1, NULL);
if (ret != 0) {
printf("生产者 1 等待失败!\n");
return 1;
}
ret = pthread_join(producer_tid2, NULL);
if (ret != 0) {
printf("生产者 2 等待失败!\n");
return 1;
}
ret = pthread_join(consumer_tid1, NULL);
if (ret != 0) {
printf("消费者 1 等待失败!\n");
return 1;
}
ret = pthread_join(consumer_tid2, NULL);
if (ret != 0) {
printf("消费者 2 等待失败!\n");
return 1;
}
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond_producer);
pthread_cond_destroy(&cond_consumer);
return 0;
}
代码示例 5:避免死锁的例子
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
void *thread_func1(void *arg) {
int thread_id = *(int *)arg;
pthread_mutex_lock(&mutex1);
printf("线程%d获取到了互斥锁 1!\n", thread_id);
sleep(1);
pthread_mutex_lock(&mutex2);
printf("线程%d获取到了互斥锁 2!\n", thread_id);
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
void *thread_func2(void *arg) {
int thread_id = *(int *)arg;
pthread_mutex_lock(&mutex1);
printf("线程%d获取到了互斥锁 1!\n", thread_id);
sleep(1);
pthread_mutex_lock(&mutex2);
printf("线程%d获取到了互斥锁 2!\n", thread_id);
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
int main() {
pthread_t tid1, tid2;
int thread_id1 = 1, thread_id2 = 2;
// 初始化互斥锁
int ret = pthread_mutex_init(&mutex1, NULL);
if (ret != 0) {
printf("互斥锁 1 初始化失败!\n");
return 1;
}
ret = pthread_mutex_init(&mutex2, NULL);
if (ret != 0) {
printf("互斥锁 2 初始化失败!\n");
return 1;
}
// 创建新线程
ret = pthread_create(&tid1, NULL, thread_func1, &thread_id1);
if (ret != 0) {
printf("线程 1 创建失败!\n");
return 1;
}
ret = pthread_create(&tid2, NULL, thread_func2, &thread_id2);
if (ret != 0) {
printf("线程 2 创建失败!\n");
return 1;
}
// 等待线程结束
ret = pthread_join(tid1, NULL);
if (ret != 0) {
printf("线程 1 等待失败!\n");
return 1;
}
ret = pthread_join(tid2, NULL);
if (ret != 0) {
printf("线程 2 等待失败!\n");
return 1;
}
// 销毁互斥锁
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}
代码示例 6:使用多线程计算数组的和
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 4
#define ARRAY_SIZE 10000
int array[ARRAY_SIZE];
long long sum = 0;
pthread_mutex_t mutex;
typedef struct {
int thread_id;
int start;
int end;
} ThreadArgs;
void *thread_func(void *arg) {
ThreadArgs *args = (ThreadArgs *)arg;
long long local_sum = 0;
for (int i = args->start; i < args->end; i++) {
local_sum += array[i];
}
pthread_mutex_lock(&mutex);
sum += local_sum;
pthread_mutex_unlock(&mutex);
printf("线程%d计算的和:%lld\n", args->thread_id, local_sum);
return NULL;
}
int main() {
pthread_t tid[NUM_THREADS];
ThreadArgs args[NUM_THREADS];
// 初始化数组
for (int i = 0; i < ARRAY_SIZE; i++) {
array[i] = i + 1;
}
// 初始化互斥锁
int ret = pthread_mutex_init(&mutex, NULL);
if (ret != 0) {
printf("互斥锁初始化失败!\n");
return 1;
}
// 创建新线程
int chunk_size = ARRAY_SIZE / NUM_THREADS;
for (int i = 0; i < NUM_THREADS; i++) {
args[i].thread_id = i + 1;
args[i].start = i * chunk_size;
if (i == NUM_THREADS - 1) {
args[i].end = ARRAY_SIZE;
} else {
args[i].end = (i + 1) * chunk_size;
}
ret = pthread_create(&tid[i], NULL, thread_func, &args[i]);
if (ret != 0) {
printf("线程%d创建失败!\n", i + 1);
return 1;
}
}
// 等待线程结束
for (int i = 0; i < NUM_THREADS; i++) {
ret = pthread_join(tid[i], NULL);
if (ret != 0) {
printf("线程%d等待失败!\n", i + 1);
return 1;
}
}
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
printf("数组的总和:%lld\n", sum);
return 0;
}
✅ 多线程与并发编程的基本概念:线程与进程的区别、并发与并行的区别
✅ 线程的创建与销毁:pthread_create、pthread_join、pthread_exit、pthread_cancel 函数
✅ 线程同步机制:互斥锁、条件变量、读写锁
✅ 线程通信机制:条件变量、信号量
✅ 并发编程的避坑指南:避免死锁、活锁、饥饿
✅ 实战案例分析:使用多线程计算数组的和、使用多线程下载文件

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online