Linux信号量操作
目录
- 信号量作用
- 函数
- 示例程序
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;
}