目录
一. 背景
在多线程编程中,同步与资源管理是保证程序正确性和性能的核心问题。线程同步用于协调多个线程对共享资源的访问,而资源管理则确保资源(如内存、文件、网络连接)的合理分配与释放。本文通过实例详解常见同步机制与资源管理策略。
二. 高效同步机制实现
1. 轻量级锁(自旋锁)与互斥锁
1.1 轻量级锁(自旋锁):
适用场景:保护执行时间极短的临界区(如计数器递增、标志位修改。
实现原理:通过 CAS(Compare-And-Swap)原子操作尝试获取锁,失败时自旋而非阻塞线程,避免上下文切换开销。
示例(基于 GCC 原子操作模拟自旋锁):
#include <stdatomic.h>
#include <stdbool.h>
typedef struct {
atomic_bool locked;
} spinlock_t;
void spinlock_init(spinlock_t* lock) {
atomic_init(&lock->locked, false);
}
void spinlock_lock(spinlock_t* lock) {
// 自旋直到成功获取锁
while (atomic_exchange(&lock->locked, true)) {
// 自旋等待(空循环)
}
}
void spinlock_unlock(spinlock_t* lock) {
atomic_store(&lock->locked, false);
}
// ------------------ 使用示例 ------------------
spinlock_t counter_lock;
int counter = 0;
void* thread_func(void* arg) {
spinlock_lock(&counter_lock);
counter++; // 临界区操作
spinlock_unlock(&counter_lock);
return NULL;
}
1.2 互斥锁
- 适用场景:临界区执行时间较长(如文件读写、数据库操作)。
- 示例(POSIX 线程互斥锁):
#include<pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int share_data = 0;
void *thread_func(void *arg)
{
pthread_mutex_lock(&mutex);
...
//TO DO;长耗时的操作如写入文件
share_data += 10;
...
pthread_mutex_unlock(&mutex);
return NULL;
}
2. 条件变量减少忙等待
作用:通过事件通知机制唤醒等待线程,避免 CPU 空转。
典型场景:生产者-消费者模型中协调缓冲区状态。
示例(生产者-消费者模型):
#include <pthread.h> #include <stdbool.h> #define BUFFER_SIZE 5 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_producer = PTHREAD_COND_INITIALIZER; pthread_cond_t cond_consumer = PTHREAD_COND_INITIALIZER; int count = 0; int buffer[BUFFER_SIZE]; void *prouducer(void *arg) { for(int i = 0; i < 10; i++) { pthread_mutex_lock(&mutex); while(count == BUFFER_SIZE) { pthread_cond_wait(&cond_producer, &mutex); } buffer[count++] = i; printf("produced:%d\n",i); pthread_cond_signal(&cond_consumer); pthread_mutex_unlock(&mutex); } return NULL; } void *consumer(void *arg) { for(int i=0,i<10;i++) { pthread_mutex_lock(&mutex); while(count == 0) { pthread_cond_wait(&cond_consumer, &mutex); } int item = buffer[--count]; printf("consumer:%d\n",item); pthread_cond_signal(&cond_proudcer); pthread_mutex_unlock(); } return NULL; }
二、优化阻塞处理的实现
1. 分离阻塞操作到独立线程
原理:将阻塞 I/O 分配到独立线程,主线程继续处理非阻塞任务。
示例(创建独立线程处理文件读取):
#include <pthread.h> #include <stido.h> #include <unistd.h> void *file_write(void *arg) { FILE *fp = NULL; fp = fopen("data.txt", "r"); if (fp) { char buffer[1024]; fread(buffer, sizeof(buffer), fp); printf("read=%s",buffer); fclose(fp); } return NULL; } int main(void) { pthread_t tid; pthread_create(&tid, NULL, file_write, NULL); printf("main task"); pthread_join(tid,NULL); return 0; }
2. 信号量与异步 I/O 提升 CPU 利用率
2.1 信号量控制并发资源
用途:限制同时访问资源的线程数量(如数据库连接池)。
示例(POSIX 信号量)
#include<semaphore.h> #include<pthread.h> #include<stdio.h> #define MAX_CONNECT_CNT 3 sem_t db_sem; void *db_process(void *arg) { sem_wait(&db_sem); printf("pthread:%ld\n", pthread_self()); sleep(1); sem_post(&db_sem); return NULL; } int main(void) { pthread_t tid[5]; sem_init(&db_sem, 0, MAX_CONNECT_CNT); for(int i = 0;i<5; i++) { pthread_create(&tid[i], NULL, db_process, NULL); pthread_join(tid[i],NULL) sem_destory(&db_sem); } return 0; }
2.2 异步 I/O 模型
原理:通过非阻塞 I/O 和回调机制分离计算与阻塞操作。
示例(Linux AIO 基本使用)
#include <aio.h> #include <fcntl.h> #include <unistd.h> void aio_callback(sigval_t sigval) { struct aiocb *req = (struct aiocb*)sigval.sival_ptr; printf("Async read completed: %s\n", (char*)req->aio_buf); } int main() { char buffer[1024]; struct aiocb req = {0}; int fd = open("data.txt", O_RDONLY); req.aio_fildes = fd; req.aio_buf = buffer; req.aio_nbytes = sizeof(buffer); req.aio_offset = 0; req.aio_sigevent.sigev_notify = SIGEV_THREAD; req.aio_sigevent.sigev_notify_function = aio_callback; req.aio_sigevent.sigev_value.sival_ptr = &req; aio_read(&req); // 发起异步读操作 // 主线程继续执行其他任务 printf("Main thread processing...\n"); sleep(2); // 等待异步操作完成 close(fd); return 0; }
三、策略总结
场景 | 技术方案 | 核心实现 |
---|---|---|
短期临界区保护 | 自旋锁(原子操作) | atomic_compare_exchange |
长耗时同步任务 | 互斥锁 + 条件变量 | pthread_mutex_lock /pthread_cond_wait |
高并发阻塞操作 | 独立线程池 + 信号量 | pthread_create /sem_wait |
非阻塞 I/O 分离 | 异步 I/O 模型 | aio_read + 回调机制 |
通过合理选择同步机制和异步模型,可显著提升多线程程序的吞吐量与响应速度。