Linux信号量操作

Linux信号量操作

目录

  1. 信号量作用
  2. 函数
  3. 示例程序

1. 信号量作用

保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。信号量的值为正(在程序中是sem.val)的时候,说明它空闲。所测试的线程可以锁定而使用它。若为 0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒。

2. 函数

(1)int semid = semget( key, 1, 0640 )

key : 信号量的键值,一般用十六进制
num = 1: 信号量的数量
0646 : 使用权限
返回值 semid 信号量的id
若信号量已经存在,返回当前信号量的id
若不存在,错因保存在errno中,errno=2,semid返回-1,不主动创建,只有当权限含有IPC_CREAT则主动创建。

(2) int semctl(int semid , int num, int cmd, ···)

semid 信号量的id
num:信号量集的下标,表示一个信号量时,填0
cmd: 命令种类,常用两个
ICP_RMID 销毁信号量,不用第四个参数
SETVAL: 初始化,第四个参数是自定义共同体,如下:

union semun   // 用于信号量默认的共同体
		{
		  int val;
		  struct semid_ds *buf;
		  unsigned short int *array;
		  struct seminfo *__buf;
		};

销毁

semctl(semid,0,IPC_RMID)

初始化

union semun sem_union;
			sem_union.val = 1;
			if( (semctl(semid,0,SETVAL,sem_union) ) <0) { perror("init semctl()"); return 0;}
(3)int semop( int semid, struct sembuf *sops, unsigned nsops)

功能:
1)等待信号量的值变为1,如果等待成功,立即把信号量的值置为0,这个过程也称之为等待锁;
2)把信号量的值置为1,这个过程也称之为释放锁。

机制:

若shortsem_op== -1, 当信号量小于1时继续等待,等信号量大于1时立刻减1
若shortsem_op== 1,对信号量加1

第三个参数 nsops是操作信号量的个数,即sops结构变量的个数,设置它的为1(只对一个信号量的操作)
第二个参数sops 是一个结构体,如下:

struct sembuf
{
	short sem_num;  /信号量集的个数,单个信号量设置为0。
	shortsem_op;  /信号量在本次操作中需要改变的数据:-1-等待操作;1-发送操作。
	shortsem_flg;  /把此标志设置为SEM UNDO,操作系统将跟踪这个信号量。
	// 如果当前进程退出时没有释放信号量,操作系统将释放信号量,避免资源被死锁。
};

示例
(1 等待信号量变为1,此时资源空闲,立即将信号量变为0,占用

struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
semop(semid, &sem_b, 1);

(2 释放资源,把信号量置1

struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
semop(semid, &sem_b, 1);

3.示例程序

(1 mysemaphore.cpp 创建信号量,并使用
(2 mysemaphore.h ShareMemoryClock.cpp 创建共享内存并加信号量锁
编译: g++ -o ShareMemoryClock ShareMemoryClock.cpp mysemaphore.h

mysemaphore.cpp

// mysemaphore.cpp

#include <cstdio>  // 含perror()
#include <sys/ipc.h> 
#include <sys/sem.h> // 信号量
#include <errno.h>  // 含环境变量errno,表示错误类型
#include <unistd.h>  // 含sleep()

class CSEM
{
	private:
		union semun   // 用于信号量默认的共同体
		{
		  int val;
		  struct semid_ds *buf;
		  unsigned short int *array;
		  struct seminfo *__buf;
		};
		int semid;
	public:
		bool init(key_t key );
		bool wait();
		bool post();
		bool destroy();
};

int main()
{
	CSEM sem;
	//初始信号灯
	if(sem.init(0x400)==false) { printf("sem.init failed.\n"); return -1; }
	printf("sem.init ok\n");
	// 等待信号灯挂出,等待成功后将持有锁
	if(sem.wait()==false) { printf("sem.wait failde.\n"); return -1;}
	printf("sem.wait ok\n");
	sleep(40); //等待过程中mysemaphore将持有锁;
	
	// 挂出信号灯,释放锁
	if(sem.post() == false) { printf("sem.post failde.\n"); return -1;}
	printf("sem.post ok\n");
	
	//销毁信号灯
	// if(sem.destroy() == false) { printf("sem.destroy failde.\n"); return -1;}
	// printf("sem.destroy ok\n");
	
}

bool CSEM::init(key_t key)
{
	//获取信号灯
	if( (semid = semget(key, 1, 0640)) == -1 )  //此时信号量未创建
	{
		// 如果信号量不存在,创建
		if(errno==2)
		{
			if( (semid = semget(key, 1, 0640|IPC_CREAT)) == -1 )
			{
				perror("init 1 semget()");
				return false;		
			}
			// 创建成功后初始化
			union semun sem_union;
			sem_union.val = 1;
			if( (semctl(semid,0,SETVAL,sem_union) ) <0) { perror("init semctl()"); return 0;}
			
		}

		else // 信号量不存在,但是创建不成功
		{
			perror("init 2 semget()"); return false;
		}
	}

	printf("simid= %d\n",semid);
	return true;
}

bool CSEM:: destroy()
{
	if( semctl(semid,0,IPC_RMID) == -1 ) { perror("wait semop()"); return false;}
	return true;
}

bool CSEM:: wait()
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1;
	sem_b.sem_flg = SEM_UNDO;
	if( semop(semid, &sem_b, 1) == -1) {perror("wait semop()"); return false;}
	return true;
}

bool CSEM::post()
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;
	if( semop(semid, &sem_b, 1) == -1){ perror("post semop()"); return false;}
	return true;
}

mysemaphore.h

// mysemaphore.h

#include <cstdio> // 含perror()
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>  // 含errno
#include <unistd.h>

class CSEM
{
	private:
		union semun   // 用于信号量默认的共同体
		{
		  int val;
		  struct semid_ds *buf;
		  unsigned short int *array;
		  struct seminfo *__buf;
		};
		int semid;
	public:
		bool init(key_t key );
		bool wait();
		bool post();
		bool destroy();
};



bool CSEM::init(key_t key)
{
	//获取信号灯
	if( (semid = semget(key, 1, 0640)) == -1 )  //此时信号量未创建
	{
		// 如果信号量不存在,创建
		if(errno==2)   // errno==2,错误类型:没有该文件或文件夹
		{
			if( (semid = semget(key, 1, 0640|IPC_CREAT)) == -1 )
			{
				perror("init 1 semget()");
				return false;		
			}
			// 创建成功后初始化
			union semun sem_union;
			sem_union.val = 1;
			if( (semctl(semid,0,SETVAL,sem_union) ) <0) { perror("init semctl()"); return 0;}
			
		}
		else
		{
			perror("init 2 semget()"); return false;
		}
	}
	return true;
}

bool CSEM:: destroy()
{
	if( semctl(semid,0,IPC_RMID) == -1 ) { perror("wait semop()"); return false;}
	return true;
}

bool CSEM:: wait()
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1;
	sem_b.sem_flg = SEM_UNDO;
	if( semop(semid, &sem_b, 1) == -1) {perror("wait semop()"); return false;}
	return true;
}

bool CSEM::post()
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;
	if( semop(semid, &sem_b, 1) == -1){perror("post semop()"); return false;}
	return true;
}


ShareMemoryClock.cpp

/* ShareMemoryClock.cpp
用锁机制实现共享内存的互斥使用
*/

#include "mysemaphore.h"  // 编译时加入
#include<sys/ipc.h>
#include<sys/shm.h> //共享内存
#include<string.h>
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct worker
{
        int age;
        char number[15];
        char name[20];
}worker;

int main()
{
	// 1.获得内存id
	int shmid = shmget( (key_t)0x8000, sizeof(worker), 0666|IPC_CREAT); 
	if(shmid == -1)
	{
			printf("(key_t)0x8000 failed\n");
			return -1;
	}
	worker*  p = NULL; //指向共享变量
	// 2.获得内存物理地址
	p = (worker*)shmat(shmid, 0, 0);
	
	// 3.读写操作,加锁
	CSEM sem;
	//初始信号灯
	if(sem.init(0x400)==false) { printf("sem.init failed.\n"); return -1; }
	printf("sem.init ok 等待资源中···\n");
	
	// 等待信号灯挂出,等待成功后将持有锁
	if(sem.wait()==false) { printf("sem.wait failde.\n"); return -1;}
	printf("sem.wait ok 获得资源,使用中···\n");
	
	// read 
	printf("写入前:%d, %s, %s\n",p->age,p->number,p->name);
	//printf("进程id:%d\n",getpid());
	// write
	sleep(30);
	p->age = 28;
	strcpy(p->number,"13984553895");
	strcpy(p->name,"张宁智");
	// read
	printf("写入后:%d, %s, %s\n",p->age,p->number,p->name);
	
	// 解锁
	if(sem.post() == false) { printf("sem.post failde.\n"); return -1;}
	printf("sem.post ok 使用资源结束,释放!\n");
	
	//sleep(30);
	// 4.从进程移除内存
	//shmdt(p); 
	//int age = p->age;
	// 5.删除共享内存
	//shmctl(shmid,IPC_RMID,0);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值