生产者消费者问题
缓冲区不满生产者才能放,缓冲区不空消费者才能拿
#define N 100
typedef int semaphore;
semaphore mutex = 1;
semaphore empty = N;
semaphore full = 0;
void producer() {
while(TRUE) {
int item = produce_item();
down(&empty); // empty--和后面full++,一个意思两个变量
down(&mutex); // 保护临界区的mutex要写在里面
insert_item(item);
up(&mutex);
up(&full);
}
}
void consumer() {
while(TRUE) {
down(&full);
down(&mutex);
int item = remove_item();
consume_item(item);
up(&mutex);
up(&empty);
}
}
读者写者问题
可以多个读,但不能同时读-写、写-写
typedef int semaphore;
semaphore data_mutex = 1; // 对写数据操作加锁
semaphore count_mutex = 1; // 对count变量加锁
int count = 0; // 读者计数
void reader() {
while(TRUE) {
down(&count_mutex);
count++;
if(count == 1) down(&data_mutex); // 第一个读者要对写数据操作加锁
up(&count_mutex);
read();
down(&count_mutex);
count--;
if(count == 0) up(&data_mutex);
up(&count_mutex);
}
}
void writer() {
while(TRUE) {
down(&data_mutex);
write();
up(&data_mutex);
}
}
哲学家就餐问题
方法一:打破"占有和等待",必须同时拿起两根筷子。
#define N 5
#define LEFT (i + N - 1) % N // 左邻居
#define RIGHT (i + 1) % N // 右邻居
#define THINKING 0
#define HUNGRY 1
#define EATING 2
typedef int semaphore;
int state[N]; // 跟踪每个哲学家的状态
semaphore mutex = 1; // 对state[]加锁
semaphore s[N]; // 每个哲学家一个信号量
void philosopher(int i) {
while(TRUE) {
think();
take_two(i);
eat();
put_two(i);
}
}
void take_two(int i) {
down(&mutex);
state[i] = HUNGRY;
test(i);
up(&mutex);
down(&s[i]);
}
void put_two(i) {
down(&mutex);
state[i] = THINKING;
test(LEFT); // 尝试唤醒邻居
test(RIGHT);
up(&mutex);
}
void test(i) { // 尝试拿起两把筷子
if(state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] !=EATING) {
state[i] = EATING;
up(&s[i]);
}
}
方法二:打破“环路等待”,所有筷子从0~N-1编号,必须先拿小编号再拿大编号。这样所有哲学家先左手后右手,但某位哲学家先右手后左手。见ctci p451。
死锁检测
用锁顺序有向图检测无环
不会死锁的LockFactory类:factory中存有无环的用锁顺序有向图G。进程向factory声明一个用锁顺序,factory尝试把用锁顺序对应的边加到G上,然后在新增用锁上dfs检查是否有环(在dfs遍历时访问到VISITING状态的节点)。若有环则删除该用锁顺序对应的边;没环就允许这个用锁顺序,并在个map中记下进程id=>用锁顺序。
见ctci p453
银行家算法
已知各进程已占有多少各资源、还需要多少各资源,总共还剩多少各资源。找出还需各资源数<剩余各资源数的进程,标记为完成,释放该进程占有的资源到剩余资源中。如此继续,最后若能标记完所有进程,则无死锁。