server.c
- #include <stdio.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/sem.h>
- #include <time.h>
- #define TIME_SEM_KEY 500
- union semun { int val ; struct semid_ds *buf ; ushort *array; };
- int semset_id; /* global for cleanup() */
- main()
- {
- union semun initval;
- struct sembuf actions; /* action set */
- int i ;
- semset_id = semget( TIME_SEM_KEY, 1, (0666|IPC_CREAT|IPC_EXCL) );
- //1表示创建一个信号量
- //IPC_CREAT 如果共享内存不存在,则创建一个共享内存,否则打开操作。
//IPC_EXCL只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。 - initval.val = 1;
- semctl(semset_id, 0, SETVAL, initval); //0表示信号量集合里面的特定信号量的号码,从0开始
- //SETVAL 表示给信号量设置初始值,即initval.val
- printf("server begin\n");
- printf("server sem num = %d\n",semctl(semset_id, 0, GETVAL, 0));
- actions.sem_num = 0;
- actions.sem_flg = SEM_UNDO; //使用SEM_UNDO的作用是,-1后加锁,如果程序意外退出,系统则会恢复此信号量 //,否则其他进程将一直阻塞在这个被锁的信号量这里。
- actions.sem_op = -1 ;
- semop( semset_id, &actions, 1); //-1操作后,信号量变为0
- printf("server sem num = %d\n",semctl(semset_id, 0, GETVAL, 0));
- for(i=0; i < 5; i++)
{
printf("server sleep %d\n", i); - printf("server sem num = %d\n",semctl(semset_id, 0, GETVAL, 0));
sleep(i); //这时候启动client进程,client进程获得不到信号量,被阻塞
}
actions.sem_num = 0;
actions.sem_flg = SEM_UNDO;
actions.sem_op = +1 ;
semop( semset_id, &actions, 1);
- sleep(2); //这时候client进程才获得了信号量
printf("server sem num = %d\n",semctl(semset_id, 0, GETVAL, 0));
semctl(semset_id, 0, IPC_RMID, initval);
}
client.c
- #include <stdio.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/sem.h>
- #include <time.h>
- #define TIME_SEM_KEY 500
- union semun { int val ; struct semid_ds *buf ; ushort *array; };
- int seg_id, semset_id; /* global for cleanup() */
- main()
- {
- 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 = 0server sleep 1
server sem num = 0server sleep 2
server sem num = 0server sleep 3
server sem num = 0server sleep 4
server sem num = 0server 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呢?
阅读(3890) | 评论(0) | 转发(2) |