System V 信号量(二)

一.进程的同步与互斥

  进程间的两种关系:同步和互斥。

       同步就是把异步环境下的一组并发进程,因直接制约而互相发送消息,二者进行互相合作、互相等待,使得各进程按一定的速度执行的过程

      互斥是指不允许两个以上的共享该资源的并发进程同时进入临界区。其中直接制约是指一组在异步环境下的并发进程,各自的执行结果互为对方的执行条件,从而限制各进程的执行速度的过程。由于共享某一共有资源而引起的在临界区内不允许并发进程交叉执行的现象,由共享共有资源而造成的对并发进程执行速度的间接制约简称为间接制约。受间接制约的类中各程序段在执行顺序上是任意的

          我们将不允许多个并发进程交叉执行的一段程序称为临界区。临界区是由属于不同并发进程的程序段共享公用数据或公用数据变量而引起的

二. 用信号量实现进程互斥

  实现如下程序:

           父进程

                      p操作

                      打印字母O

                      sleep

                      打印字母O

                      V操作

                      sleep()

           子进程

                      p操作

                      打印字母X

                      sleep

                      打印字母X

                      V操作

                      sleep()

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

#define ERR_EXIT(m)\
	do\
	{ \
		perror(m); \
		exit(EXIT_FAILURE); \
	}while(0)

 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) */
           };
           
// 创建信号量集
int sem_create(key_t key)
{
	int semid = semget(key,1,0666 | IPC_CREAT | IPC_EXCL);
	if(semid < 0)
		ERR_EXIT("semget err");
	return semid;
}


// P操作
int sem_p(int semid)
{
	struct sembuf sb = {0,-1,0};
	int ret = semop(semid,&sb,1);//nops指出opsptr指向的sembuf结构数组中元素的数目
	if(ret < 0)
		ERR_EXIT("semop err");
	return ret;
}

// V操作
int sem_v(int semid)
{
	struct sembuf sb = {0,1,0};
	int ret = semop(semid,&sb,1);
	if(ret < 0)
		ERR_EXIT("semop err");
	return ret;
}

// 删除信号量
int sem_d(int semid)
{
	int ret = semctl(semid,0,IPC_RMID,0);
	if(ret < 0)
		 ERR_EXIT("semctl err");
	return ret;
}

// 设置信号量集中的信号量的计数值
int sem_setval(int semid,int val )
{
	union semun su;
	su.val = val;
	//int semctl(int semid 标识, int semnum (0,1,...,nsems-1), int cmd(GETVAL,SETVAL,), ...);
	int ret = semctl(semid,0,SETVAL,su); // su作为值传送的,不是按引用传送的,
	if(ret < 0)
	 	ERR_EXIT("semctl err");
	printf("value updated ....\n");
	return ret;
}


int semid;

void print(char op_char)
{
	int pause_time;
	srand(getpid());
	int i=0;
	for(;i<10;i++)
	{
		sem_p(semid);   // P操作
		printf("%c",op_char);
		fflush(stdout); // 清空缓冲区
		pause_time = rand()%3; // 睡眠时间为0,1,2 中一个
		sleep(pause_time);
		printf("%c",op_char);
		fflush(stdout);
		sem_v(semid);  // V操作
		// PV操作之外的
		pause_time = rand()%3;
		sleep(pause_time);
	}
	//printf("\n");
}

int main(int argc,char* argv[])
{
	semid = sem_create(IPC_PRIVATE);
	sem_setval(semid,0);  // 开始信号量计数值为0
	pid_t pid;
	pid = fork();
	if(pid < 0)
		 ERR_EXIT("fork err");
	if(pid > 0)  // 父进程
	{
		sem_setval(semid,1); //设置信号量集中的信号量的计数值为1
		print('O');  // 调用上面的print函数
	}
	else  // 子进程
	{
		print('X');
	}
	// 有一个进程早退出,会先调用sem_d(semid),导致另外一个进程执行pv操作出现错误.所有先注释掉下行代码
//	sem_d(semid);
	return 0;
}

分析: 父子两个进程调用同一个函数,但是函数内部用的是PV操作,调用代码段执行的是原子操作,打印的字符必须是成对出现的.最好sem_d(semld); 代码注释掉了,因为有一个进程肯定会早一步退出循环,执行这个语句,导致另一个进程执行PV操作出现错误.暂时没有处理信号量的删除操作.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值