142-Comunicación entre procesos (semáforo)

Recursos críticos : recursos a los que solo un proceso o subproceso puede acceder a la vez.
Áreas críticas : segmentos de código que acceden a recursos críticos,
como: probadores de centros comerciales,
sincronización de encrucijadas : control para asegurar la corrección de la ejecución del programa , usa semáforos

El semáforo es una variable especial y generalmente toma un valor positivo. Su valor representa el número de recursos que están autorizados a acceder. Cuando se obtiene un recurso, el valor de las necesidades de semáforo a reducirse atómicamente por uno. Esta operación se llama la operación P .
Cuando el valor del semáforo es 0, significa que no hay recursos disponibles y se bloqueará la operación P.
Al liberar los recursos, es necesario agregar atómicamente uno al valor del semáforo. Esta operación se llama la operación V .
Los semáforos se utilizan principalmente para sincronizar procesos. Si el valor del semáforo solo toma 0, 1, se llama semáforo binario .
Si el valor del semáforo es mayor que 1, se denomina semáforo de conteo . Por ejemplo, hay 3 probadores para 3 personas, la cuarta persona debe esperar a que la
operación fotovoltaica pase la garantía de
atomicidad para la adquisición y liberación de recursos a su vez, y no habrá problemas.

Por ejemplo:
n representa el número restante de boletos de tren.
Todos compran un boleto, n-1
dos personas compran un boleto, debería ser n-2, de hecho, n-1
porque la compra del boleto es un proceso concurrente, la
computadora necesita que uno reduzca el valor de n en 1. Durante el proceso, n = 5 lee al procesador y se prepara para disminuir en 1, lo que no se ha completado. Al mismo tiempo, otro visita, también lee n = 5 para el procesador, se prepara para decrementar 1, y los dos últimos procesos escriben 4
an = 4
Inserte la descripción de la imagen aquí

Este resultado 4 es obviamente problemático,
por lo que necesitamos controlar, no controlar n al mismo tiempo.
Necesitamos usar el semáforo de la operación atómica para resolver este problema.
A través de la operación PV 0,1

Ejemplo 2: El
acceso a la impresora
Inserte la descripción de la imagen aquí
necesita ser controlado por un semáforo
Inserte la descripción de la imagen aquí
Primero, A realiza la operación P para obtener el valor del semáforo (1), resta 1, y es 0.
Antes de ejecutar V, A está en uso. En este momento, B accede, operación p, encuentro semáforo 0, bloque

vi ac
Inserte la descripción de la imagen aquí
vi bc
Inserte la descripción de la imagen aquí
simultáneamente en el mismo terminal
Inserte la descripción de la imagen aquí

Ahora use el semáforo para resolver el problema de la siguiente manera

Introducción de la interfaz del semáforo operativo:

#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
/*
semget()创建或者获取已存在的信号量
semget()成功返回信号量的 ID, 失败返回-1
key:两个进程使用相同的 key 值,就可以使用同一个信号量
nsems:内核维护的是一个信号量集,在新建信号量时,其指定信号量集中信号
量的个数
semflg 可选: IPC_CREAT IPC_EXCL
*/

int semget(key_t key, int nsems, int semflg);//创建,获取信号量

/*
semop()对信号量进行改变,做 P 操作或者 V 操作
semop()成功返回 0,失败返回-1
struct sembuf
{
unsigned short sem_num; //指定信号量集中的信号量下标
short sem_op; //其值为-1,代表 P 操作,其值为 1,代表 V 操作
short sem_flg; //SEM_UNDO
};
*/

int semop(int semid, struct sembuf *sops, unsigned nsops);//初始化

/*
semctl()控制信号量
semctl()成功返回 0,失败返回-1
cmd 选项: SETVAL IPC_RMID

union semun
{
int val;
struct semid_ds *buf;
unsigned short *array
struct seminfo *_buf;
}; */

int semctl(int semid, int semnum, int cmd, ...);

Inserte la descripción de la imagen aquí
Interfaz para encapsular semáforo:
Inserte la descripción de la imagen aquí

vi sem.h.

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

union semun{
    
    
	int val;//初始值 
};

void sem_init();//创建/或者已存在的信号量
void sem_p();//p 减一
void sem_v();//v 加一
void sem_destroy();//销毁

usted sem.c.

#include "sem.h"

static int semid = -1;

void sem_init()//创建/或者已存在的信号量
{
    
    
	semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);//约定都使用这个key_t值,1个信号量,全新创建
	if ( semid == -1 )//已存在
	{
    
    
		semid = semget((key_t)1234,1,0600);//存在就直接获取
	}
	else
	{
    
    
		union semun a;

		a.val = 1;//信号量的初始值
		if ( semctl(semid,0,SETVAL,a) == -1 )//下标为0,初始化失败
		{
    
    
			perror("semctl error");
		}
	}
}

void sem_p()//p 减一
{
    
    
	struct sembuf buf;
	buf.sem_num = 0;//成员下标
	buf.sem_op = -1;//p
	buf.sem_flg = SEM_UNDO;

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

void sem_v()//v 加一
{
    
    
	struct sembuf buf;
	buf.sem_num = 0;//成员下标
	buf.sem_op = 1;//v
	buf.sem_flg = SEM_UNDO;

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

void sem_destroy()//销毁
{
    
    
	if ( semctl(semid,0,IPC_RMID) == -1 )
	{
    
    
		perror("semctl del error");
	}
}

vi ac

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main()
{
    
    
	sem_init();//初始化1
	int i = 0;
	for( ;i < 10; i++ )
	{
    
    
		sem_p();//如果检测到1,通过,减1
		printf("a");
		fflush(stdout);
		int n = rand() % 3;
		sleep(n);
		printf("a");
		fflush(stdout);
		sem_v();

		n = rand() % 3;
		sleep(n);
	}
}

Inserte la descripción de la imagen aquí
vi bc

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main()
{
    
    
	sem_init();
	int i = 0;
	for( ;i < 10; i++ )
	{
    
    
		sem_p();
		printf("b");
		fflush(stdout);
		int n = rand() % 3;
		sleep(n);
		printf("b");
		fflush(stdout);
		sem_v();

		n = rand() % 3;
		sleep(n);
	}
}

Inserte la descripción de la imagen aquí
Compilar y ejecutar
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Este semáforo es creado por nosotros informando al kernel, y el kernel lo mantendrá
. Una vez que terminemos, el kernel aún se mantiene
y el semáforo puede estar en uso.

Solo se puede eliminar una vez

Inserte la descripción de la imagen aquí
Después de usarlo, debemos eliminarlo, de lo contrario no sabemos si es 1 o 0 (la última vez).
Usa el comando para eliminar.
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Mira la siguiente pregunta:

Los tres procesos a, byc ingresan "A", "B" y "C" respectivamente, y el resultado de salida debe ser "ABCABCABC ..."

El primero de los tres semáforos se inicializa a 1 y los dos últimos se inicializan a 0. ps1 pasa por
Inserte la descripción de la imagen aquí
primera vez, ps2 ps3 no pasa
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquíInserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquíInserte la descripción de la imagen aquí
vi ac
Inserte la descripción de la imagen aquí

vi bc
Inserte la descripción de la imagen aquí

vi cc
Inserte la descripción de la imagen aquí
correr
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/LINZEYU666/article/details/112899094
Recomendado
Clasificación