面试题答案
一键面试1. 使用信号量实现进程间同步与互斥
信号量本质上是一个计数器,它通过控制访问共享资源的进程数量来实现同步与互斥。
初始化信号量
#include <semaphore.h>
sem_t semaphore;
// 初始化信号量为1,代表同一时间只允许一个进程访问共享资源
sem_init(&semaphore, 0, 1);
这里sem_init
函数第一个参数是指向sem_t
类型变量的指针,第二个参数表示信号量是否在多个进程间共享(0表示不共享,1表示共享),第三个参数是信号量的初始值。
获取信号量(进入临界区)
sem_wait(&semaphore);
sem_wait
函数会将信号量的值减1,如果信号量的值为0,那么这个函数会阻塞,直到信号量的值大于0。
释放信号量(离开临界区)
sem_post(&semaphore);
sem_post
函数会将信号量的值加1,唤醒因等待该信号量而阻塞的进程。
2. 使用互斥锁实现进程间同步与互斥
互斥锁本质上是特殊的二元信号量(值为0或1),用于保护共享资源,保证同一时间只有一个进程能够访问共享资源。
初始化互斥锁
#include <pthread.h>
pthread_mutex_t mutex;
// 初始化互斥锁
pthread_mutex_init(&mutex, NULL);
pthread_mutex_init
函数第一个参数是指向pthread_mutex_t
类型变量的指针,第二个参数用于设置互斥锁的属性(一般为NULL
)。
锁定互斥锁(进入临界区)
pthread_mutex_lock(&mutex);
如果互斥锁当前处于解锁状态,pthread_mutex_lock
函数会将其锁定并返回;如果互斥锁已被锁定,该函数会阻塞直到互斥锁被解锁。
解锁互斥锁(离开临界区)
pthread_mutex_unlock(&mutex);
pthread_mutex_unlock
函数会将互斥锁解锁,唤醒因等待该互斥锁而阻塞的进程。
3. 高并发场景下可能出现的同步问题及解决方案
同步问题 - 竞态条件
在高并发场景下,多个进程可能同时访问和修改共享资源,导致数据不一致。例如,多个进程同时对一个共享的计数器进行加1操作:
// 共享计数器
int counter = 0;
// 进程1
void *process1(void *arg) {
int temp = counter;
temp++;
counter = temp;
return NULL;
}
// 进程2
void *process2(void *arg) {
int temp = counter;
temp++;
counter = temp;
return NULL;
}
如果进程1和进程2同时执行上述代码,可能会出现竞态条件,导致最终的counter
值比预期少1。
解决方案
使用信号量或互斥锁来解决竞态条件问题。以互斥锁为例:
#include <pthread.h>
pthread_mutex_t mutex;
int counter = 0;
// 进程1
void *process1(void *arg) {
pthread_mutex_lock(&mutex);
int temp = counter;
temp++;
counter = temp;
pthread_mutex_unlock(&mutex);
return NULL;
}
// 进程2
void *process2(void *arg) {
pthread_mutex_lock(&mutex);
int temp = counter;
temp++;
counter = temp;
pthread_mutex_unlock(&mutex);
return NULL;
}
通过在访问共享资源counter
前后分别锁定和解锁互斥锁,保证同一时间只有一个进程能够访问和修改counter
,从而避免竞态条件。