pthread_t t1, t2;
union semun initval;
struct sembuf actions; /* action set */
semset_id = semget( TIME_SEM_KEY, 1, 0 );
actions.sem_num = 0; /* sem[0] is n_readers */
actions.sem_flg = SEM_UNDO; /* auto cleanup */
actions.sem_op = -1 ; /* wait til no readers */
printf(“client begin\n”);
semop( semset_id, &actions, 1); //此时信号量已经为0,所以-1操作会被阻塞
actions.sem_num = 0; /* sem[0] is n_readers */
actions.sem_flg = SEM_UNDO; /* auto cleanup */
actions.sem_op = +1 ; /* wait til no readers */
semop( semset_id, &actions, 1);
printf(“client over\n”);
}
运行结果:
./server
server begin
server sem num = 1
server sem num = 0
server sleep 0
server sem num = 0
server sleep 1
server sem num = 0
server sleep 2
server sem num = 0
server sleep 3
server sem num = 0
server sleep 4
server sem num = 0
server sem num = 1
./client
client begin
client over
comments:
server进程运行后,输出此时信号量是1, -1操作后锁住信号量,输出信号量是0,然后进入睡眠
client进程运行后,输出“client begin”后,-1操作被阻塞在那里,因为此时信号量已经为0,等待server醒来
server醒来后,+1操作释放信号量,将信号量值变为1, 进入睡眠
client进程获得可用信号量,-1操作锁住信号量,+1操作释放信号量,运行结束,输出client over
server醒来后,输出此时信号量是1,并结束
一些信号量的理论知识:
P1和P2是分别将数据送入缓冲B和从缓冲B读出数据的两个进程, 为了防止这两个进程并发时产生错误,狄克斯特拉设计了一种同步机制叫“PV操作”,P操作和V操作是执行时不被打断的两个操作系统原语。
1. 执行P操作P(S)信号量S值减1,若结果不为负则P(S)执行完毕,否则执行P操作的进程暂停等待释放。
2. 执行V操作V(S)时,S的值加1,若结果不大于0则释放一个因执行P(S)而等待的进程。
对P1和P2可定义两个信号量S1和S2,初值分别为1和0.
1. 进程P1在向缓冲B送入数据前执行P 操作P(S1),在送入数据后执行V操作V(S2)。
2. 进程P2在从缓冲B读取数据前先执行P操作P(S2),在读出数据后执行V操作V(S1)。
3. 当P1往缓冲B送入一数据后信号量S1之值变为0,在该数据读出后S1之值才又变为1,因此在前一数未读出前后一数不会送入,从而保证了P1和P2之间的同步。
一般来说,信号量S>=0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S<0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。
有个问题是server的进程在循环的时候,这时候client进程已经运行并由于尝试对信号量做-1操作而导致信号量<0,从而client被阻塞,那么这时候为啥从server里获得的当前的信号量的值还是0呢?为啥不是-1呢?