进程间的通讯方式_信号量

信号量

       当我们编写的程序使用了线程时,不管它是运行在多用户系统上、多线程系统上,还是运行在多用户多进程系统上,我们通常会发现程序中存在着一部分临界代码,我们需要只有一个进程(或一个执行线程)可以进入这个临界代码并拥有对资源独占式的访问权。为了防止出现因多个程序同时访问一个共享资源而引发的问题,我们需要有一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。信号量的一个更正式的定义式是:它是一个特殊变量,只允许对它进行等待(wait)和发送信号(signal)这两种操作。

1. 临界资源

    同一时刻只能被一个进程访问的资源

2. 临界区

    访问临界资源代码区域

3. 原子操作

    任何情况下都不能被打断的操作

4. 内核对象

    用于对进程间通讯时,多进程能够访问同一资源的记录

信号量的作用:进程间同步控制,信号量相当于记录资源能够同时被多少个进程访问

信号量的操作:

       创建或获取:如果是创建,必须初始化;如果获取,则不能初始化。

       减一操作:P 操作

       加一操作:V 操作

       删除:

信号量操作的相关函数:

       int semget((key_t)key, int nsems, int flag);   //创建或者获取

            第一个参数 key 是整数值,不相关的进程可以通过它访问同一个信号量。

            nsems 参数指定需要的信号量数目,它几乎总是取值为1。

            flag 参数是一组标志,它与 open 的函数标志非常相似。

       int semop(int semid, struct sembuf *buf, int lenyh);   //P  V 操作,用于改变信号量的值

            第一个参数 semid 是有semget返回的信号量标识符。

            第二个参数 buf 是指向一个结构体数组的指针,每个数组元素至少包括以下几个成员:

                   struct sembuf

                   {

                       short sem_num;    //信号量编号

                       short sem_op;    //信号量在一次操作中需要改变的值,-1为 P 操作,+1为 V 操作

                       short sem_flg;   

                   }

       int semctl(int semid, int pos, int cmd, /*union semun un*/);

            cmd 参数为将要采取的动作。

练习:A 进程输入“OK”,B 进程输出数字0~9。

代码如下:

#ifndef _SEM_H
#define _SEM_H

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

int semid;

union semun
{
	int val;
};

void sem_get();
void sem_p();
void sem_v();
void sem_del();

#endif
#include "sem.h"

void sem_get()
{
	semid = semget((key_t)1234, 1, 0664);
	if (semid == -1)
	{
		semid = semget((key_t)1234, 1, 0664 | IPC_CREAT);
		assert(semid != -1);

		union semun v;
		v.val = 0;
		if (semctl(semid, 0, SETVAL, v) == -1)
		{
			perror("error");
			exit(0);
		}
	}
}

void sem_p()
{
	struct sembuf buffer;
	buffer.sem_num = 0;
	buffer.sem_op = -1;
	buffer.sem_flg = SEM_UNDO;

	if (semop(semid, &buffer, 1) == -1)
	{
		perror("p error");
		exit(0);
	}
}

void sem_v()
{
	struct sembuf buffer;
	buffer.sem_num = 0;
	buffer.sem_op = 1;
	buffer.sem_flg = SEM_UNDO;

	if (semop(semid, &buffer, 1) == -1)
	{
		perror("v error");
		exit(0);
	}
}

void sem_del()
{
	if (semctl(semid, 0, IPC_RMID) == -1)
	{
		perror("del error");
		exit(0);
	}
}

进程 A 代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
//#include <sys/ipc.h>
//#include <sys/sem.h>
#include "sem.h"
#include "sem.c"

int main()
{
	sem_get();

	while (1)
	{
		printf("Please input: ");
		fflush(stdout);

		char buffer[128] = {0};
		fgets(buffer, 127, stdin);
		buffer[strlen(buffer)-1] = 0;

		if (strncmp(buffer, "OK", 2) == 0)
		{
			sem_v();
		}

		if (strncmp(buffer, "end", 3) == 0)
		{
			break;
		}
	}
	sem_del();
	return 0;
}

B 进程代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
//#include <sys/ipc.h>
//#include <sys/sem.h>
#include "sem.h"
#include "sem.c"

int main()
{
	sem_get();
	sem_p();
	for (int i=0; i<10; i++)
	{
		printf("%d \n", i);
	}

	sem_del();
	return 0;
}





猜你喜欢

转载自blog.csdn.net/ylh_yanlinghui/article/details/78379799