同步机制
- 信号量:信号量是一个整型变量,它通过计数器来控制对共享资源的访问。例如,当信号量的值大于0时,表示有可用的资源,进程可以获取信号量(计数器减1)来访问共享资源;当信号量的值为0时,表示资源已被占用,进程需要等待。
- 互斥锁:互斥锁本质上是一种特殊的二元信号量(值只能为0或1)。它用于保证在同一时刻只有一个进程能够访问共享资源,通过加锁(将值设为0)和解锁(将值设为1)操作来实现。
- 条件变量:条件变量通常与互斥锁一起使用。它允许进程在某个条件满足时被唤醒。例如,在生产者 - 消费者模型中,消费者进程可以在共享缓冲区不为空的条件下被唤醒。
代码层面优化
- 减少信号量操作次数:避免在频繁执行的代码段中进行信号量的获取和释放操作,尽量将信号量操作放在关键的同步点。
- 合理设置缓冲区大小:根据实际需求设置共享内存缓冲区的大小,避免缓冲区过小导致频繁的读写操作,或过大造成内存浪费。
- 预读和预写:在生产者 - 消费者模型中,生产者可以提前将数据写入缓冲区的空闲位置,消费者可以提前读取缓冲区中的数据,提高整体效率。
生产者 - 消费者模型C语言实现
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <pthread.h>
#define BUFFER_SIZE 5
#define PRODUCE_NUM 20
// 共享内存结构体
typedef struct {
int buffer[BUFFER_SIZE];
int in;
int out;
} SharedData;
SharedData *shared_data;
sem_t *empty;
sem_t *full;
sem_t *mutex;
// 生产者线程函数
void *producer(void *arg) {
int i, item;
for (i = 0; i < PRODUCE_NUM; i++) {
item = i;
sem_wait(empty); // 等待缓冲区有空闲位置
sem_wait(mutex); // 进入临界区
shared_data->buffer[shared_data->in] = item;
printf("Produced: %d\n", item);
shared_data->in = (shared_data->in + 1) % BUFFER_SIZE;
sem_post(mutex); // 离开临界区
sem_post(full); // 通知缓冲区有新数据
}
return NULL;
}
// 消费者线程函数
void *consumer(void *arg) {
int i, item;
for (i = 0; i < PRODUCE_NUM; i++) {
sem_wait(full); // 等待缓冲区有数据
sem_wait(mutex); // 进入临界区
item = shared_data->buffer[shared_data->out];
printf("Consumed: %d\n", item);
shared_data->out = (shared_data->out + 1) % BUFFER_SIZE;
sem_post(mutex); // 离开临界区
sem_post(empty); // 通知缓冲区有空闲位置
}
return NULL;
}
int main() {
key_t key;
int shmid;
pthread_t producer_thread, consumer_thread;
// 创建共享内存
key = ftok(".", 'a');
shmid = shmget(key, sizeof(SharedData), IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget");
exit(1);
}
shared_data = (SharedData *)shmat(shmid, NULL, 0);
if (shared_data == (void *)-1) {
perror("shmat");
exit(1);
}
shared_data->in = 0;
shared_data->out = 0;
// 创建信号量
empty = sem_open("/empty", O_CREAT, 0666, BUFFER_SIZE);
full = sem_open("/full", O_CREAT, 0666, 0);
mutex = sem_open("/mutex", O_CREAT, 0666, 1);
if (empty == SEM_FAILED || full == SEM_FAILED || mutex == SEM_FAILED) {
perror("sem_open");
exit(1);
}
// 创建生产者和消费者线程
if (pthread_create(&producer_thread, NULL, producer, NULL) != 0) {
perror("pthread_create producer");
exit(1);
}
if (pthread_create(&consumer_thread, NULL, consumer, NULL) != 0) {
perror("pthread_create consumer");
exit(1);
}
// 等待线程结束
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
// 销毁信号量
sem_close(empty);
sem_close(full);
sem_close(mutex);
sem_unlink("/empty");
sem_unlink("/full");
sem_unlink("/mutex");
// 分离共享内存
if (shmdt(shared_data) == -1) {
perror("shmdt");
exit(1);
}
// 删除共享内存
if (shmctl(shmid, IPC_RMID, NULL) == -1) {
perror("shmctl");
exit(1);
}
return 0;
}