关于名字,老师课件上写信号量,实验教材上却写信号灯。这种概念,叫来叫去的概念的东西适合不去理解东西的女生去背。然后觉得知道的东西很多一样每次都说其中一个时都把另一个名字也说出来。
我喜欢通俗的理解一下,在前两遍的时候没有什么概念,这次就仔细找生活中的概念。我想起来我坐过的火车,那上边的卫生间,目前没坐过硬座以外的火车,就拿我见过的来说吧。卫生间绝对算是一个临界资源了,这个很好理解,它就一个xx,所以一次只能一个人(进程)上(访问)。
那个能亮“有人”的指示灯的作用就很好理解,没人的时候是不亮的,有人的时候立即显示“有人”。其它人就不能访问。这不就是一个活生生的信号量例子。那一车厢的人就是进程,他们都要上一个只能一个人同时上的卫生间。
同样在火车上上厕所也能总结出步骤来:1建好厕所和指示灯 2将灯设为无人状态 3一人进厕所 灯显示为“有人”状态 4 方便完 出来 灯重新显示为“无人”状态 5 拆出厕所和指示灯。其实上边的第一步和第五步是为了引到信号量中硬套上去的,没有人会这样做。
根据火车上上厕所的经历,信号量的作用和用法都出来了。
比喻完了,就该说点正经的,在没学习这个的时候就在mini2440的adc驱动和tc驱动之间看到了信号量的踪迹。但是那是驱动程序,那也算是进程吗?这都还是未解的。
在这期间老师给我举了一个高雅的例子:打印机。不过意思是相同的。
看一个例子:test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include <unistd.h>
int main()
{
int pid, semid;
key_t semkey;
int val;
if((semkey = ftok("./test.c",1))<0)
{
printf("ftok failed\n");
exit(EXIT_FAILURE);
}
printf("ftok ok, semkey = %d\n", semkey);
if((semid = semget(semkey, 1, IPC_CREAT|IPC_EXCL|0700))<0)
{
printf("semget failed\n");
exit(EXIT_FAILURE);
}
printf("semget ok, semid=%d\n", semid);
if((semctl(semid, 0, SETVAL, 1))<0)
{
printf("semctl set semval failed\n");
exit(EXIT_FAILURE);
}
printf("semctl set semval ok\n");
if((pid = fork())<0)
{
printf("fork failed\n");
exit(EXIT_FAILURE);
}
else if(pid>0)
{
struct sembuf p_op_buf, v_op_buf;
p_op_buf.sem_num = 0;
p_op_buf.sem_op = -1;
if(semop(semid, &p_op_buf, 1)<0)
{
printf("semop failed\n");
exit(EXIT_FAILURE);
}
printf("father get the semaphore\n");
v_op_buf.sem_num = 0;
v_op_buf.sem_op = 1;
v_op_buf.sem_flg = 0;
if(semop(semid, &v_op_buf, 1)<0)
{
printf("semop release semaphore failed\n");
exit(EXIT_FAILURE);
}
wait(NULL);
}
else
{
struct sembuf p_op_buf, v_op_buf;
sleep(1);
printf("child wait for the semaphore\n");
p_op_buf.sem_num = 0;
p_op_buf.sem_op = -1;
p_op_buf.sem_flg = 0;
if(semop(semid, &p_op_buf, 1)<0)
{
printf("semop get semaphore failed\n");
exit(EXIT_FAILURE);
}
printf("child get the semaphore\n");
if(semctl(semid, 0, IPC_RMID, 0)< 0)
{
printf("semctl remove semaphore set failed\n");
exit(EXIT_FAILURE);
}
}
return 0;
}
运行结果:
[root@localhost Desktop]# ./a.out
ftok ok, semkey = 16795729
semget ok, semid=163843
semctl set semval ok
father get the semaphore
child wait for the semaphore
child get the semaphore
[root@localhost Desktop]#
在做完这个例子后我其实不能明白这个在这里边的作用,一个进程获取一下然后释放。另一个进程同样这样做。真没有什么意思。但是我想到了 adc 和 tc的例子。它们只是同时要用,然后信号量就有了,又但是不是说只让一个用,而不让另一个用,而是做一个调解。让一个进程用一下。再让另一个用一下,这样就不会造成某个进程不能用这个资源 了,上边的程序运行一次真没有什么意思。如果多次意思就出来了。
另外关于 计数信号灯 这个现实中的例子莫过于是一个生意很好的饭店中的空的桌子的数量了,人特别多,都在外边排队,50张桌子递减,来一桌人就减一,到0的时候就不能再进人了,如果走一桌又从0+1=1了,就可以再进一桌人了。这个资源是可以这样来的。