您的位置:首页 > 运维架构 > Linux

LinuxC/C++编程(5)—SystemV信号量

2016-05-25 18:33 337 查看
Linux中有多种类型的信号量,其中SystemV是比较重要的一种,常用于多进程同步和进程间通信。常用的函数均包含于<sys/sem.h>中。

参考了一篇很不错的博客文章:点击打开链接

自己写了一个程序,两个进程分别向控制台打印字符串,两个进程几乎一样,只是B进程中没有初始化/删除信号量。
贴代码:

这是A进程,信号量在这个进程中被初始化和删除

//============================================================================
// Name        : A.cpp
// Author      : Lin
// Version     :
// Copyright   : Your copyright notice
// Description : A demo for processes synchronization using SystemV
//============================================================================

#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/sem.h>
#include <time.h>
#include <stdlib.h>
using namespace std;

union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};

/*******这个子函数用于创建信号量*******/
int createSem()
{
int semId = semget((key_t)1234, 1, 0666|IPC_CREAT);//包含于<sys/sem.h>,创建一个信号量,共用一个key_t key即表示共用一个信号量
if (semId < 0)
{
cerr << "create SystemV error! "<< endl;
return -1;
}
else
return semId;
}

/*******这个子函数用于初始化信号量*******/
int setSem(int semId)
{
union semun se;
se.val = 1;//设置信号量的初始值为1
if (semctl(semId, 0, SETVAL, se) == -1)//初始化这个信号量
{
cerr << "init fail!" << endl;
return -1;
}
else
return 0;
}

/*******这个子函数删除信号量*******/
int delSem(int semId)
{
union semun se;
if (semctl(semId, 0, IPC_RMID, se) < 0)
{
cerr << "delete fail!" << endl;
return -1;
}
else
return 0;
}

/*******信号量P(等待)V(发布)操作*******/
int P_Sem(int semId)
{
struct sembuf buf;
buf.sem_num = 0;//操作单个信号量的时候该参数为0
buf.sem_op = -1; //-1表示P操作,1表示V操作
buf.sem_flg = SEM_UNDO;
if (semop(semId, &buf, 1) < 0)
{
cerr << "P error!" << endl;
return -1;
}
else
return 0;
}

int V_Sem(int semId)
{
struct sembuf buf;
buf.sem_num = 0;//操作单个信号量的时候该参数为0
buf.sem_op = 1; //-1表示P操作,1表示V操作
buf.sem_flg = SEM_UNDO;
if (semop(semId, &buf, 1) < 0)
{
cerr << "V error!" << endl;
return -1;
}
else
return 0;
}

/*******主函数*******/
int main() {
string str = "a";
int semId = createSem();
if (semId == -1)
return -1;
if (setSem(semId) == -1) //一个信号量只能被初始化/删除一次
return -1;
double d = 0;
srand(time(NULL)); //设置随机数的种子
for (int i = 0; i != 10; ++i)
{
P_Sem(semId); //进入临界区
d = rand()*1.0/RAND_MAX;  //产生一个0-1之间的随机数,让线程休眠这段时间
cout << str << i << " " << d << endl;
sleep(d);
V_Sem(semId); //离开临界区
}

P_Sem(semId);
if (delSem(semId) == -1) //一个信号量只能被初始化/删除一次
return -1;
return 0;
}

这是B进程,在这个进程中没有信号量的初始化函数,所以这个函数需要先在后台运行,然后再运行A进程(否则这个B进程会因为信号量未被初始化而一直被阻塞)

//============================================================================
// Name        : B.cpp
// Author      : Lin
// Version     :
// Copyright   : Your copyright notice
// Description : A demo for processes synchronization using SystemV
//============================================================================

#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/sem.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};

/*******这个子函数用于创建信号量*******/
int createSem()
{
int semId = semget((key_t)1234, 1, 0666|IPC_CREAT);//包含于<sys/sem.h>,创建一个信号量,共用一个key_t key即表示共用一个信号量
if (semId < 0)
{
cerr << "create SystemV error! "<< endl;
return -1;
}
else
return semId;
}

/*******这个子函数用于初始化信号量*******/
int setSem(int semId)
{
union semun se;
se.val = 1;//设置信号量的初始值为1
if (semctl(semId, 0, SETVAL, se) == -1)//初始化这个信号量
{
cerr << "init fail!" << endl;
return -1;
}
else
return 0;
}

/*******这个子函数删除信号量*******/
int delSem(int semId)
{
union semun se;
if (semctl(semId, 0, IPC_RMID, se) < 0)
{
cerr << "delete fail!" << endl;
return -1;
}
else
return 0;
}

/*******信号量P(等待)V(发布)操作*******/
int P_Sem(int semId)
{
struct sembuf buf;
buf.sem_num = 0;//操作单个信号量的时候该参数为0
buf.sem_op = -1; //-1表示P操作,1表示V操作
buf.sem_flg = SEM_UNDO;
if (semop(semId, &buf, 1) < 0)
{
cerr << "P error!" << endl;
return -1;
}
else
return 0;
}

int V_Sem(int semId)
{
struct sembuf buf;
buf.sem_num = 0;//操作单个信号量的时候该参数为0
buf.sem_op = 1; //-1表示P操作,1表示V操作
buf.sem_flg = SEM_UNDO;
if (semop(semId, &buf, 1) < 0)
{
cerr << "V error!" << endl;
return -1;
}
else
return 0;
}

/*******主函数*******/
int main() {
string str = "b";
int semId = createSem();

if (semId == -1)
return -1;

double d = 0;
srand(time(NULL)); //设置随机数的种子
for (int i = 0; i != 10; ++i)
{
P_Sem(semId); //进入临界区
d = rand()*2.0/RAND_MAX;
cout << str << i << " " << d << endl;
sleep(d);
V_Sem(semId); //离开临界区
}

return 0;
}


运行过程如下:先后台运行B进程,再运行A进程

lin@lin-Z97-HD3:~/workspace$ ./B &

[1] 9733

lin@lin-Z97-HD3:~/workspace$ ./A

b0 1.87174

a0 0.274022

b1 0.902205

a1 0.555554

b2 1.49148

a2 0.541172

b3 1.86328

a3 1.59087

b4 1.99479

a4 1.65941

b5 0.353798

a5 0.54769

b6 0.637533

a6 1.29195

b7 0.618795

a7 1.9387

b8 0.38083

a8 1.70235

b9 0.727489

a9 0.851653

[1]+  已完成               ./B

可以看到两个进程轮流向控制台打印字符串
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: