(1)信号量本质上是一个具有原子性的计数器,用来描述临界资源的,不能用全局变量count加加减减替换(因为他没有原子性)。
(2)信号量以保护临界资源为目的,但他本身也是个临界资源;他控制多个进程对共享资源的访问,通常描述临界资源当中,临界资源的数量,常常被当做锁来使用,防止一个进程访问另外一个进程正在使用的资源
(3)其中最简单的信号量=1,也叫做二元信号量(互斥锁),可控制单个资源,只能取0和1;信号量>=2为多元信号量
只要理理解上面三句话,应该结合代码理解就不难了。
代码实现相关函数:
#include
#include
key_t ftok(const char* pathname,int id)//pathname:路径名 id:项目id,非0整数(只有低8位有效)
//2.semget函数
int semget(key_t key,int nsems,int semflg);
//参数:key-->信号集的名字
//nsems:信号集中信号量的个数
//semflg:由九个权限构成,用法和创建文件时使用的mode模式一样
//返回值:成功返回一个非负整数,即该信号集的标识码;失败返回-1
创建成功后,Linux下通过ipcs -s可以查看已经创建的信号量情况,删除使用删除:ipcrm -s semid
//semctl函数
int semctl(int semid,int semnum,int cmd,...);
//参数:
//semid:mesget返回的信号集标识码
//semnum:信号集中信号量的序号
//cmd:将要采取的动作(有三个取值,一般用于销毁)
//最后一个参数根据命令不同而不同
//返回值:成功返回0;失败返回-1
代码实测;
我们用两个进程分别对一个文件进行读写:
1.sem.h
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
union semun
{
int val;
};
void sem_init();//初始化
void sem_p();//P操作 +1
void sem_v();//V操作 -1
void sem_destroy();//销毁
2.sem.cpp
#include "sem.h"
static int semid = 0;
void sem_init()
{
semid = semget((key_t)1234, 1, IPC_CREAT | IPC_EXCL | 0600);//不存在则创建,已经存在返回-1
if (semid == -1)
{
semid = semget((key_t)1234, 1, IPC_CREAT | 0600);//返回-1之后获取他的semid
if (semid == -1)
{
printf("semget error");
}
}
else
{
semun a;//a传值
a.val = 1;
if (semctl(semid, 0, SETVAL, a) == -1)//0代表信号量下标,设置这个下标的值
{
perror("semctl init error");
}
}
}
void sem_p()
{
struct sembuf buf;
buf.sem_num = 0;////对下标为0的进行操作,刚刚设置了
buf.sem_op = -1;//p操作,若val<0进行V操作信号量值加val,即a.val=a.val-1
buf.sem_flg = SEM_UNDO;//设置在进程出现错误时信号量值自动恢复,防止一个进程占着信号量
if (semop(semid, &buf, 1) == -1)
{
perror("p error");
}
}
void sem_v()
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1; //若val > 0进行V操作信号量值加val,即a.val = a.val + 1
buf.sem_flg = SEM_UNDO;
if (semop(semid, &buf, 1) == -1)
{
perror("v error");
}
}
void sem_destroy()
{
if (semctl(semid, 0, IPC_RMID) == -1)
{
perror("semctl destroy error");
}
printf("sem destory success!\n");
}
3.proA.cpp
#include"sem.h"
#include
using namespace std;
void file_write(int x);
int main()
{
int a = 0;
sem_init();
for (int i = 0; i < 20; i++)
{
sem_p();
a++;
file_write(a);
sem_v();
sleep(1);
}
sleep(2);
destory_sem();//由进程A来销毁这个信号量jin
return 0;
}
void file_write(int x)
{
const char*fpath = "/home/ubuntu/test.txt";
FILE* file = fopen(fpath, "a+");//打开可读可写文件,不存在则创建
char buf[11] = "A:write:";//方便区分
buf[8] = x + '0';
buf[9] = '\n';
buf[10] = '\0';
fwrite(buf, 1, strlen(buf), file);
fclose(file);
}
4.proB.cpp
#include"sem.h"
#include
using namespace std;
void file_write(int x);
int main()
{
int a = 0;
sem_init();
for (int i = 0; i < 20; i++)
{
sem_p();
a++;
file_write(a);
sem_v();
sleep(1);
}
return 0;
}
void file_write(int x)
{
const char*fpath = "/home/ubuntu/test.txt";
FILE* file = fopen(fpath, "a+");//打开可读可写文件,不存在则创建
char buf[11] = "B:write:";//方便区分
buf[8] = x + '0';
buf[9] = '\n';
buf[10] = '\0';
fwrite(buf, 1, strlen(buf), file);
fclose(file);
}