一.什么是信号量呢?用途又是什么呢?
信号量就是解决进程之间竞争资源的情况,比如:我们在宿舍用的公共洗衣机,我们只有当它空闲的时候,我们才可以去使用它,当别人看到洗衣机在使用的时候,就不能再去使用了。这个例子中,洗衣机就是资源,每个想洗衣服的人都想去占用资源。但是我们得等当前的前一个人洗完才可以使用,这就是等待。
首先我们来看Linux下的几个信号量相关的函数:
1.int semget(key_t key, int nsems, int semflg);
这个函数可以用来初始化信号量或者获得当前的信号量,当无法初始化的时候,返回的值为-1。使用时是这样。第一个参数是设置key_t的值,第二个是信号量的个数。第三个是通过bash来获取信号量的信息。
-
semid =
semget((
key_t)
1234,
1, IPC_CREAT | IPC_EXCL |
0600);
//用来初始化信号量,如果信号量的key_t值已存在的话就返回-1
-
semid =
semget((
key_t)
1234,
1,
0600);
//获取已经存在信号量的key_t值,如果已存在返回当前key_t。如果没有,返回-1
2.semctl(int semid, int semnum, int cmd, ...);
返回的是当前信号量的key值(usigned int)类型的,通常用获取或者删除某个信号量,使用方法如下
-
semctl(semid,
0, SETVAL, a)
//这个是初始化当前semid信号量第0+1个元素的值,a为下方结构体
-
union
semun {
-
int val;
/* Value for SETVAL */
-
struct
semid_ds *buf;
/* Buffer for IPC_STAT, IPC_SET */
-
unsigned
short *array;
/* Array for GETALL, SETALL */
-
struct
seminfo *__buf;
/* Buffer for IPC_INFO
-
(Linux-specific) */
-
};
//需要程序员去定义
-
semctl(semid,
0, IPC_RMID);
//这个是删除当前semid对应的信号量
3. semop(semid, &buf, 1) ;(这些函数都可以通过bash命令man来找到原型)
用来获取或者释放当前资源,其中buf是定义好的结构体,结构体成员sem_op为1的时候就是释放资源,为-1则是占用资源
-
struct
sembuf buf;
-
buf.sem_num =
0;
-
buf.sem_op =
1;
-
buf.sem_flg = SEM_UNDO;
-
semop(semid, &buf,
1);
//第一个参数是当前信号量的id,第二个参数就是提到的结构体,第三个参数是如果程序异常退出的话,我们可以释放它所占用的资源
4.Ok,逻辑成立,理论实践。
介绍一下文件的结构把,先来编辑
只看.从.c和.h文件,文字描述一下把。sem.h文件中声明了四个方法,比如信号量的初始化,资源的释放和占用,信号量的销毁、
sem.c文件就是队sem.h头文件的实现。
main.c和test.c就是两个进程,我们两个进程都占用屏幕来输出,但是我们再同一时间,只想让一个进程来使用我们的屏幕,这就得用来我们的信号量。下面我们来看一看各个文件的具体实现把。
1.sem.h
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <string.h>
-
#include <sys/sem.h>
-
-
union
semun {
-
int val;
-
};
-
-
void sem_init();
-
void sem_p();
-
void sem_v();
-
void sem_destory();
2.sem.c
-
#include "sem.h"
-
#include <sys/sem.h>
-
#include <sys/types.h>
-
-
static
int semid =
-1;
-
-
void sem_init() {
-
semid =
semget((
key_t)
1234,
1, IPC_CREAT | IPC_EXCL |
0600);
-
if (semid ==
-1) {
-
semid =
semget((
key_t)
1234,
1,
0600);
-
if (semid ==
-1) {
-
printf(
"semget err\n");
-
}
-
}
else {
-
union semun a;
-
a.val =
1;
-
if (
semctl(semid,
0, SETVAL, a) ==
-
-1) {
//此时我们只需要一个变量,所以下标为0
-
printf(
"semctl err\n");
-
}
-
}q
-
}
-
void sem_p() {
-
struct
sembuf buf;
-
buf.sem_num =
0;
-
buf.sem_op =
-1;
-
buf.sem_flg = SEM_UNDO;
-
if (
semop(semid, &buf,
1) ==
-1) {
-
printf(
"p err\n");
-
}
-
}
-
void sem_v() {
-
struct
sembuf buf;
-
buf.sem_num =
0;
-
buf.sem_op =
1;
-
buf.sem_flg = SEM_UNDO;
-
if (
semop(semid, &buf,
1) ==
-1) {
-
printf(
"v err\n");
-
}
-
}
-
void sem_destory() {
-
if (
semctl(semid,
0, IPC_RMID) ==
-1) {
-
printf(
"semvtl err\n");
-
}
-
}
3.main.c
-
#include "sem.h"
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <unistd.h>
-
int main() {
-
sem_init();
-
for (
int i =
0; i <
5; i++) {
-
sem_p();
-
printf(
"B");
-
fflush(stdout);
-
int n =
rand() %
3;
-
sleep(n);
-
printf(
"B");
-
fflush(stdout);
-
sem_v();
-
sleep(n);
-
}
-
sleep(
10);
-
sem_destory();
-
}
4.test.c
-
#include "sem.h"
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <unistd.h>
-
int main() {
-
sem_init();
-
for (
int i =
0; i <
5; i++) {
-
sem_p();
-
printf(
"A");
-
fflush(stdout);
-
int n =
rand() %
3;
-
sleep(n);
-
printf(
"A");
-
fflush(stdout);
-
sem_v();
-
sleep(n);
-
}
-
}
5.进程间通信几个文件进行运行的话和普通文件的编译也不一样,所以CV之前的代码只是半九十,我们来看一下编译吧
这是编译时候的代码 ,运行结果如下,最后一行的最左侧有个B,别忘记了。困惑了我半天。