面试题答案
一键面试1. 利用条件变量结合互斥锁实现同步逻辑
在C语言的Linux共享内存编程中,结合条件变量和互斥锁实现同步逻辑的步骤如下:
- 初始化互斥锁和条件变量:
- 使用
pthread_mutex_init
初始化互斥锁。 - 使用
pthread_cond_init
初始化条件变量。
- 使用
- 进程获取互斥锁:在访问共享内存前,每个进程都要先获取互斥锁,以确保同一时间只有一个进程能访问共享内存。
- 检查共享内存数据状态:获取互斥锁后,进程检查共享内存中的数据状态,判断是否满足特定条件。
- 等待条件变量:如果条件不满足,进程调用
pthread_cond_wait
等待条件变量。pthread_cond_wait
会自动释放互斥锁,使其他进程能够访问共享内存。当条件满足被唤醒时,pthread_cond_wait
会重新获取互斥锁。 - 满足条件后进行处理:当条件满足时,进程进行相应的处理,处理完成后释放互斥锁。
2. 条件变量相较于信号量在这种场景下的优势
- 精准唤醒:条件变量可以精准地唤醒等待特定条件的线程,而信号量是一种更通用的计数器,唤醒的线程不一定是等待特定条件的,可能需要额外的判断。
- 避免虚假唤醒:虽然条件变量也可能出现虚假唤醒,但通过合理的编程(如在循环中检查条件),可以有效避免这种情况。而信号量在某些复杂场景下,可能更容易出现资源竞争和误唤醒的问题。
- 与互斥锁紧密结合:条件变量通常与互斥锁紧密配合使用,更适合在需要保护共享资源并等待特定条件的场景中,而信号量更侧重于资源计数和一般的同步控制。
3. 具体代码示例及关键代码行解释
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SHM_SIZE 1024
// 共享内存结构体
typedef struct {
int data;
pthread_mutex_t mutex;
pthread_cond_t cond;
} SharedData;
// 生产者线程函数
void* producer(void* arg) {
SharedData* shared = (SharedData*)arg;
for (int i = 0; i < 5; ++i) {
pthread_mutex_lock(&shared->mutex);
shared->data = i;
printf("Producer set data to %d\n", i);
pthread_cond_signal(&shared->cond);
pthread_mutex_unlock(&shared->mutex);
sleep(1);
}
return NULL;
}
// 消费者线程函数
void* consumer(void* arg) {
SharedData* shared = (SharedData*)arg;
for (int i = 0; i < 5; ++i) {
pthread_mutex_lock(&shared->mutex);
while (shared->data < i) {
pthread_cond_wait(&shared->cond, &shared->mutex);
}
printf("Consumer got data %d\n", shared->data);
pthread_mutex_unlock(&shared->mutex);
}
return NULL;
}
int main() {
int shm_fd;
SharedData* shared;
// 创建共享内存对象
shm_fd = shm_open("/shared_memory", O_CREAT | O_RDWR, 0666);
if (shm_fd == -1) {
perror("shm_open");
return 1;
}
// 设置共享内存大小
if (ftruncate(shm_fd, SHM_SIZE) == -1) {
perror("ftruncate");
return 1;
}
// 映射共享内存到进程地址空间
shared = (SharedData*)mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shared == MAP_FAILED) {
perror("mmap");
return 1;
}
// 初始化互斥锁和条件变量
pthread_mutex_init(&shared->mutex, NULL);
pthread_cond_init(&shared->cond, NULL);
pthread_t producer_thread, consumer_thread;
// 创建生产者和消费者线程
if (pthread_create(&producer_thread, NULL, producer, shared) != 0) {
perror("pthread_create producer");
return 1;
}
if (pthread_create(&consumer_thread, NULL, consumer, shared) != 0) {
perror("pthread_create consumer");
return 1;
}
// 等待线程结束
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&shared->mutex);
pthread_cond_destroy(&shared->cond);
// 取消映射并关闭共享内存
if (munmap(shared, SHM_SIZE) == -1) {
perror("munmap");
return 1;
}
if (close(shm_fd) == -1) {
perror("close");
return 1;
}
if (shm_unlink("/shared_memory") == -1) {
perror("shm_unlink");
return 1;
}
return 0;
}
关键代码行解释:
pthread_mutex_lock(&shared->mutex);
:获取互斥锁,保护共享内存的访问。while (shared->data < i) { pthread_cond_wait(&shared->cond, &shared->mutex); }
:消费者线程检查条件,不满足则等待条件变量,pthread_cond_wait
会自动释放互斥锁并在唤醒时重新获取。pthread_cond_signal(&shared->cond);
:生产者线程设置数据后,发送信号唤醒等待的消费者线程。pthread_mutex_unlock(&shared->mutex);
:操作完成后释放互斥锁。pthread_mutex_init(&shared->mutex, NULL);
和pthread_cond_init(&shared->cond, NULL);
:初始化互斥锁和条件变量。pthread_mutex_destroy(&shared->mutex);
和pthread_cond_destroy(&shared->cond);
:销毁互斥锁和条件变量。