/*
* 進程間通信之信號量,代碼源自《Linux程序設計》
*/
#include <iostream>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
// 使用信號量必須包含該文件
#include <sys/sem.h>
using namespace std;
// 自定義的一個聯合體,信號量相關函數需要使用
union semun
{
int val;
struct semid_ds* buf;
unsigned short* array;
};
// 初始化信號量
int set_semvalue(int semid)
{
union semun sem_union;
// 信號量的初始值是1
sem_union.val = 1;
// 使用semctl函數去設置它,參數為SETVAL
if(semctl(semid,0,SETVAL,sem_union) == -1)
{
cout << "set_semvalue failed!"<< endl;
return 0;
}
return 1;
}
// 刪除一個信號量
int del_semvalue(int semid)
{
union semun sem_union;
// 使用semctl去刪除它,標志是IPC_RMID
if(semctl(semid,0,IPC_RMID,sem_union) == -1)
{
cout << "del_semvalue failed!"<< endl;
return 0;
}
return 1;
}
// 等待信號量
int semaphore_p(int semid)
{
struct sembuf sem_b;
sem_b.sem_num = 0; // 如果不是使用一組信號,那麼這個值一般都是0
sem_b.sem_op = -1; // 表示進行P操作
sem_b.sem_flg = SEM_UNDO; // 默認都要設置為SEM_UNDO(這是為了,當進程異常退出的時候,系統可以釋放進程持有的信號量)
// 調用semop進行P操作
if(semop(semid,&sem_b,1) == -1)
{
cout << "semaphore_p failed!"<< endl;
return 0;
}
return 1;
}
// V操作,釋放信號量
int semaphore_v(int semid)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1; // 1表示進行V操作
sem_b.sem_flg = SEM_UNDO;
if(semop(semid,&sem_b,1) == -1)
{
cout << "semaphore_v failed!"<< endl;
return 0;
}
return 1;
}
int main(int argc,char* argv[])
{
// 信號量的id
int sem_id;
char op_char = 'O';
// 創建或者打開一個信號量(信號量不存在就創建、存在就打開)
sem_id = semget((key_t)1234,1,0666|IPC_CREAT);
// 用一個額外的參數去控制哪個進程對信號量進行初始化,即如果當前進程有額外的參數
// 那麼它就對信號量進行初始化
if(argc > 1)
{
// 初始化信號量
if(set_semvalue(sem_id) == 0)
{
return -1;
}
op_char = 'X';
sleep(2);
}
for(int i = 0; i < 10; ++i)
{
// 等待信號量
if(semaphore_p(sem_id) == 0)
{
return -1;
}
// 打印一些信息
cout << op_char ;
cout.flush();
sleep(2);
cout << op_char;
cout.flush();
// 釋放信號量,即V操作
if(semaphore_v(sem_id) == 0)
{
return -1;
}
sleep(2);
}
// 執行結束,打印一些信息
cout << endl << getpid() << " - finished" << endl;
// 用額外的參數去控制進程去刪除信號量
if(argc > 1)
{
if(del_semvalue(sem_id) == 0)
{
return -1;
}
}
return 0;
}