信号量:相当于一个计数器,描述当前环境下临界资源的数目。信号量是用来保护临界资源的,而信号量本身也是临界资源。
生命周期:随内核。
原子性:即要么做,要么不做。
临界资源:不同进程可以看到的同一资源。
临界区:不同进程访问同一资源的代码区(write(),read())。
互斥:任一时刻,只有一个进程进入临界区访问临界资源,且访问时具有原子性。
同步:所有进程以某种顺序依次访问临界资源。
信号量的两个基本操作:P、V操作-----解决互斥和同步的问题。
P操作:申请资源,如果S>0,则S=S-1;如果S = 0,就挂起该进程的执行。
V操作:使用资源完毕,归还给系统,若有进程挂起,则唤醒等待进程,否则S=S+1。
代码如下:
comm.h:
#ifndef _COMM_H
#define _COMM_H
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#define PATHNAME "."
#define PROJ_ID 0666
union semun{
int val;
struct semid_ds *buf;
unsigned
short *
array;
struct seminfo *__buf;
};
//struct sembuf{
// unsigned short sem_num; // semaphore number
// short sem_op; // semaphore operation
// short sem_flg; //operation flags
//};
int create_sem(int nsem);
int get_sem();
int destroy_sem(int semid);
int init_sem(int semid,int which,int val);
int P(int semid,int which);
int V(int semid,int which);
#endif
comm.c:
#include"comm.h"
static int comm_sem(int nsem ,int flag)
{
key_t key=ftok(PATHNAME,PROJ_ID);
int semid=semget(key,nsem,flag);
if(semid<
0){
perror(
"semget");
}
return semid;
}
static op_sem(int semid,int op,int which)
{
struct sembuf _sembuf;
_sembuf.sem_op = op;
_sembuf.sem_num = which;
_sembuf.sem_flg =
0;
return semop(semid,&_sembuf,
1);
}
int create_sem(int nsem)
{
return comm_sem(nsem,IPC_CREAT|IPC_EXCL|
0666);
}
int get_sem()
{
return comm_sem(
0,IPC_CREAT);
}
int destroy_sem(int semid)
{
if(semctl(semid,
0,IPC_RMID)<
0)
{
perror(
"semctl");
return -
1;
}
//printf("destroy sucess");
return
0;
}
int init_sem(int semid,int which,int _val)
{
union semun _semun;
_semun.val = _val;
if(semctl(semid,which,SETVAL,_semun)<
0)
{
perror(
"semctl");
return -
2;
}
return
0;
}
int P(int semid,int which)
{
return op_sem(semid,-
1,which);
}
int V(int semid,int which)
{
return op_sem(semid,
1,which);
}
sem.c:
#include"comm.h"
#include<stdlib.h>
int main()
{
int semid=create_sem(
10);
init_sem(semid,
0,
1);
pid_t id=fork();
if(id<
0)
{
perror(
"fork");
return -
1;
}
else
if(id ==
0){
//child
int sem_id=get_sem();
while(
1)
{
P(sem_id,
0);
printf(
"A");
fflush(
stdout);
usleep(
12345);
printf(
"A");
fflush(
stdout);
usleep(
13456);
V(sem_id,
0);
}
exit(
0);
}
else{
//father
while(
1)
{
P(semid,
0);
printf(
"B");
fflush(
stdout);
usleep(
14345);
printf(
"B");
fflush(
stdout);
usleep(
13345);
V(semid,
0);
}
wait(
NULL);
}
destroy_sem(semid);
return
0;
}
Makefile:
sem:comm.c sem.c
gcc -o $@ $^
.PHONY:cleam
clean:
rm -f sem