Linux系统信号量机制互斥访问共享内存区进行进程间通信
实现代码
#include <bits/stdc++.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <sys/shm.h>
using namespace std;
const int DELAY = 1;
const int BUFFER_SIZE = 1024;
const int SIGMA = 26;
union Semaphore {
int value;
semid_ds *buffer;
unsigned short *array;
seminfo *infomation;
};
static int shareMemoryID;
static int semaphoreID;
static bool initializeSemaphoreValue() {
Semaphore semaphoreUnion;
semaphoreUnion.value = 1;
return semctl(semaphoreID, 0, SETVAL, semaphoreUnion) == -1 ? false : true;
}
static bool semaphoreP() {
sembuf semaphoreBuffer;
semaphoreBuffer.sem_num = 0;
semaphoreBuffer.sem_op = -1;
semaphoreBuffer.sem_flg = SEM_UNDO;
return semop(semaphoreID, &semaphoreBuffer, 1) == -1 ? false : true;
}
static bool semaphoreV() {
sembuf semaphoreBuffer;
semaphoreBuffer.sem_num = 0;
semaphoreBuffer.sem_op = 1;
semaphoreBuffer.sem_flg = SEM_UNDO;
return semop(semaphoreID, &semaphoreBuffer, 1) == -1 ? false : true;
}
static void deleteSemaphoreSet() {
Semaphore semaphoreUnion;
if (semctl(semaphoreID, 0, IPC_RMID, semaphoreUnion) == -1) {
fprintf(stderr, "Failed to delete semaphore\n");
}
}
int main(int argc, char const *argv[])
{
if ((semaphoreID = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT)) == -1) {
fprintf(stderr, "Create semaphore set failed!\n");
abort();
}
if (!initializeSemaphoreValue()) {
fprintf(stderr, "Initialize semaphore failed!\n");
abort();
}
if ((shareMemoryID = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666 | IPC_CREAT)) == -1) {
fprintf(stderr, "Shared memory created fail!\n");
abort();
}
pid_t pid = fork();
if (pid == -1) {
perror("Fork fail!\n");
abort();
} else {
char *buffer = (char*)shmat(shareMemoryID, NULL, 0);
if (pid == 0) {
while (true) {
if (!semaphoreP()) {
printf("Semaphore P failed!\n");
abort();
}
char ch = *buffer;
*buffer = tolower(ch);
if (!semaphoreV()) {
printf("Semaphore V failed!\n");
abort();
}
if (ch == 'Z') {
break;
}
}
} else {
for (int i = 0; i < SIGMA; i++) {
if (!semaphoreP()) {
printf("Semaphore P failed!\n");
abort();
}
*buffer = 'A' + i;
if (!semaphoreV()) {
printf("Semaphore V failed!\n");
abort();
}
usleep(100);
if (!semaphoreP()) {
printf("Semaphore P failed!\n");
abort();
}
printf("%c", *buffer);
fflush(stdout);
if (!semaphoreV()) {
printf("Semaphore V failed!\n");
abort();
}
sleep(DELAY);
}
}
if (shmdt(buffer) == -1) {
fprintf(stderr, "Delete share memory failed!\n");
abort();
}
}
if (pid > 0) {
wait(NULL);
deleteSemaphoreSet();
}
return 0;
}
相关函数
shmat()
- 函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg)
- 参数
- shmid为共享内存标识符
- shmaddr指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
- shmflg为读写权限,设为SHM_RDONLY为只读模式,其他为读写模式
- 返回值
成功返回附加好的共享内存地址,否则返回-1
- 功能
连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问
shmget()
- 函数原型
int shmget(key_t key, size_t size, int shmflg)
- 参数
- key为相应键值
- size为新建共享内存大小
- shmflg为读写权限
- 返回值
成功则返回共享内存标志符,否则返回-1
- 功能
得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符
shmdt()
- 函数原型
int shmdt(const void *shmaddr)
- 参数
- shmaddr为连接的共享内存的起始地址
- 返回值
成功返回0,否则返回-1
- 功能
断开与共享内存附加点的地址,禁止本进程访问此片共享内存
输出结果
abcdefghijklmnopqrstuvwxyz
注意
- 若注释掉信号量相关代码,不能保证两个进程互斥访问共享内存区,将会得到意料之外的结果
鸣谢
最后
- 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!