操作系统实验——互斥与同步

本文介绍了进程和线程间的同步互斥机制,包括SYSTEMV和POSIX信号量的使用,互斥锁与条件变量的应用,并通过多个实例展示如何解决实际问题。

目录

1.SYSTEM V信号量

(1) 创建或打开:semget    

(2) 申请或释放:semop    

(3) 设置信号量:semctl    

2.POSIX信号量

(1) 初始化:sem_init

(2) 申请和释放:sem_wait

(3) 销毁:sem_destroy

(4) 获得信号量值:sem_getvalue:

3.进程同步与互斥

(1)进程互斥

(2)进程同步

4.线程同步与互斥

(1)互斥锁实现线程互斥

(2)条件变量实现线程同步

(3)信号量实现线程同步

5.综合实例


Linux系统上存在两套信号量标准:SYSTEM V信号量和POSIX信号量。

1.SYSTEM V信号量

头文件:

#inlclude <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

(1) 创建或打开:semget    

int semget(key_t key, int nsems, int semflg);    

成功返回信号量ID,失败返回-1

key:信号量集键值,常用ICP_PRIVATE由系统分配

nsems:信号量个数

semflg:常用IPC_CREAT代表没有新建信号量集则创建

m=semget(IPC_PRIVATE,1,0666|IPC_CREAT);

新建一个只有一个信号量的私有信号量集m

(2) 申请或释放:semop    

int semop(int semid, struct sembuf *sops, unsigned nsops);    

semid:信号量集ID

sops:操作定义的结构体

nsops:操作次数

semop(m,&sem_b,1);

struct sembuf sem_b;

sem_b.semnum=0;//要操作的信号量在信号量集中的索引,从0开始

sem_b.sem_op=-1;//负P正V

sem_b.sem_flg=SEM_UNDO;//进程意外结束时,进行UNDO

利用sem_b对m信号量集中索引为0的第一个信号做wait(P)操作

sem_b长度为1,意思是只做一个操作

进程意外结束时,将已做的wait进行UNDO

(3) 设置信号量:semctl    

int semctl(int semid, int semnum, int cmd, union semun arg);    

semid:信号量集ID

semnum:要操作的信号量在信号量集中的索引,从0开始

cmd:要执行的命令

        SETVAL:设置一个信号量值

        GETVAL:返回一个信号量值

arg:与cmd搭配使用

semctl(m,0,SETVAL,1);

设置信号量集m中第一个信号量的初值为1

2.POSIX信号量

(1) 初始化:sem_init

int sem_init(sem_t *sem, int pshared, unsigned int value);

sem:指向信号量的指针

pshared:0代表当前进程的所有线程共享,1代表进程间共享

value:信号量初值

(2) 申请和释放:sem_wait

int sem_wait(sem_t *sem);

减1为0则阻塞

int sem_post(sem_t *sem);

数值加1

(3) 销毁:sem_destroy

int sem_destroy(sem_t *sem);

sem:指向信号量的指针

(4) 获得信号量值:sem_getvalue:

int sem_getvalue(sem_t *sem, int *sval);

sem:指向信号量的指针

sval:获得的值保存在sval中

获得信号量的值,若阻塞则获得阻塞的进程/线程数,值保存到sval中

3.进程同步与互斥

(1)进程互斥

设有一个房间资源,一次只能一个进程使用,用信号量操作模拟3个进程互斥使用房间,输入q杀死进程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>

//5-13:进程互斥
int room = 0;
char ch;

int main(int argc,char argv[]) {
	pid_t pid;
	pid_t pids[2];
	int i=0;
	int j=0;
	struct sembuf sem_b;
	sem_b.sem_num=0;
	sem_b.sem_flg=SEM_UNDO;
	//创建控制进入房间的信号量
	room=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
	//互斥信号量room赋初值为1
	semctl(room,0,SETVAL,1);
     
	for (i=0;i<=2;i++) {
		pid=fork();//父亲循环几次,创建几个子进程。子进程由于while(1)不进入for循环
		if (pid==0){
		    while(1){//子进程循环,父亲不进
		        printf("%d want to  enter room--WAIT\n",getpid());
		        sem_b.sem_op = -1;        //申请资源,操作数为1      
		        semop(room,&sem_b,1);    //此两句是信号量操作的申请wait        
		        printf("%d is in room\n",getpid());           
		        sleep(3);                 
		        sem_b.sem_op = 1;        //释放资源,操作数为1            
		        semop(room,&sem_b,1);    //此两句是信号量操作的释放signal          
		        printf("%d is out of room---SIGNAL OK\n",getpid());
		    }//while
		} 
		else{ 
			pids[i]=pid;//父亲
		}
	}//for
	
	do{
		ch=getchar();
		if (ch == 'q')
		    for (i=0;i<=2;i++)
		        kill(pids[i],SIGTERM);
	 }while(ch != 'q');
} //main

父亲for循环3次,生成3个儿子,3个儿子进出房间

(2)进程同步

1个盘子能放1个水果,儿子读书累了就拿水果吃,没有水果就等待;父亲和母亲都不断给儿子放水果,盘子满了就不能放。用信号量操作模拟这3个进程的运行过程。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>

//5-14:进程同步
int e;        //empty of plate
int f;        //fruit

int waitsem(int sem_id) {
//把信号量操作封装到函数中,提高代码可读性
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1;
	sem_b.sem_flg = SEM_UNDO;
	if(semop(sem_id,&sem_b,1) == -1){
                fprintf(stderr, "P failed\n");
                return 0;        }//if
        return 1;        
}

int signalsem(int sem_id){
        struct sembuf sem_b;
        sem_b.sem_num = 0;
        sem_b.sem_op =  1;
        sem_b.sem_flg = SEM_UNDO;
        if(semop(sem_id,&sem_b,1) == -1){
                fprintf(stderr, "V failed\n");
                return 0;        }//if
        return 1;        
}

int main(int argc,char argv[]){
	pid_t pid;
	pid_t pids[2];
	int i=0;
	char ch;
      e=semget(IPC_PRIVATE,1,0666|IPC_CREAT);    
	//创建e信号量用于控制对 盘子空资源 的使用
      f=semget(IPC_PRIVATE,1,0666|IPC_CREAT);    
	//创建f信号量用于控制对 水果
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值