LinuxC进程间通信之共享内存、信号量综合实例
公共接口
#ifndef __INTERFACE_H
#define __INTERFACE_H
#include <stdio.h>
#define LOGI(fmt, ...) do { \
printf("[INFO][%s:%d]"fmt"", __func__, __LINE__, ##__VA_ARGS__); \
} while(0)
#define LOGE(fmt, ...) do { \
printf("[ERROR][%s:%d]"fmt"", __func__, __LINE__, ##__VA_ARGS__); \
} while(0)
#define KEY_PATHNAME (".")
#define KEY_PROJECT_ID ('R')
#define SEMAPHORE_NUMS (1)
#define SHM_SEM_PERMISSION (0666)
#define PRINT_A (0)
#define PRINT_B (1)
#define PRINT_A_B_2S (2)
#define PRINT_A_B_250MS (3)
#define PRINT_TYPE0 (0)
#define PRINT_TYPE1 (1)
#define PRINT_TYPE2 (2)
#define DEALY_1MS (1000)
#define DELAY_1S (1000 * DEALY_1MS)
#define DEALY_2S (2 * DELAY_1S)
#define DELAY_250MS (250 * DEALY_1MS)
#define SEM_CTRL_V (1)
#define SEM_CTRL_P (-1)
typedef struct {
unsigned int type;
unsigned int *state;
} PrintThreadInfoHandle;
typedef struct {
unsigned int type;
unsigned int state;
} ShmInfoHandle;
int IPC_SemShmIdInit(int *semId, int *shmId);
int IPC_SemaphoreCtrl(int semId, int type);
int IPC_DestorySemShm(int semId, int shmId);
int ChangePrintState(int type, int state);
#endif
/ ******************************************* /
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include "interface.h"
int IPC_SemShmIdInit(int *semId, int *shmId)
{
if (semId == NULL || shmId == NULL) {
LOGE("semId or shmId is NULL\n");
return -1;
}
key_t key = 0;
key = ftok(KEY_PATHNAME, KEY_PROJECT_ID);
if (key < 0) {
LOGE("Get key failed. err:%s\n", strerror(errno));
return -1;
}
LOGI("Get key successful. key:%#x\n", key);
*semId = semget(key, SEMAPHORE_NUMS, IPC_CREAT | SHM_SEM_PERMISSION);
if (*semId < 0) {
LOGE("Get semId failed. err:%s\n", strerror(errno));
return -1;
}
*shmId = shmget(key, sizeof(ShmInfoHandle), IPC_CREAT | SHM_SEM_PERMISSION);
if (*shmId < 0) {
LOGE("Get shmId failed. err:%s\n", strerror(errno));
return -1;
}
LOGI("Get semId and shmId successful. semId:%#x, shmId:%#x\n", *semId, *shmId);
return 0;
}
int IPC_DestorySemShm(int semId, int shmId)
{
int ret = 0;
ret = semctl(semId, 0, IPC_RMID);
if (ret < 0) {
LOGE("Destory sem failed. err:%s\n", strerror(errno));
}
ret = shmctl(shmId,IPC_RMID,NULL);
if (ret < 0) {
LOGE("Destory shm failed. err:%s\n", strerror(errno));
}
LOGI("call IPC_DestorySemShm successful.\n");
return 0;
}
int IPC_SemaphoreCtrl(int semId, int type)
{
if (type != SEM_CTRL_P && type != SEM_CTRL_V) {
LOGE("type is failed.\n");
return -1;
}
int ret = 0;
struct sembuf semBuf;
semBuf.sem_num = 0;
semBuf.sem_op = type;
semBuf.sem_flg = SEM_UNDO;
ret = semop(semId, &semBuf, 1);
if (ret < 0) {
LOGE("call semop failed. semId:%d, type:%d\n", semId, type);
return -1;
}
return 0;
}
int ChangePrintState(int type, int state)
{
int semId;
int shmId;
int ret = 0;
ShmInfoHandle *info = NULL;
ret = IPC_SemShmIdInit(&semId, &shmId);
if (ret != 0) {
LOGE("call IPC_SamShaIdInit failed.");
return -1;
}
info = (ShmInfoHandle *)shmat(shmId, NULL, 0);
if (info == (void *)-1) {
LOGE("Get shm Addr failed. err:%s", strerror(errno));
return 0;
}
info->type = type;
info->state = state;
IPC_SemaphoreCtrl(semId, SEM_CTRL_V);
LOGI("ChangePrintState successful. type:%d state:%d\n", type, state);
return 0;
}
进程1代码
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include "interface.h"
unsigned int print0State;
unsigned int print1State;
unsigned int print2State;
PrintThreadInfoHandle g_printThreadInfo[3] = { \
{PRINT_TYPE0, &print0State}, \
{PRINT_TYPE1, &print1State}, \
{PRINT_TYPE2, &print2State}, \
};
static void *PrintThreadFunc(void *arg)
{
if (arg == NULL) {
LOGE("arg is null, start print thread failed.\n");
return (void *)-1;
}
PrintThreadInfoHandle *info = NULL;
info = (PrintThreadInfoHandle *)arg;
LOGI("Start PrintThreadFunc type:%d p_state:%p\n", info->type, info->state);
while (1) {
switch (*info->state) {
case PRINT_A:
LOGI("type:%d PRINT_A---\n", info->type);
break;
case PRINT_B:
LOGI("type:%d PRINT_B---\n", info->type);
break;
case PRINT_A_B_2S:
while (*info->state == PRINT_A_B_2S) {
LOGI("type:%d PRINT_A_B_2S---A---\n", info->type);
usleep(DEALY_2S);
LOGI("type:%d PRINT_A_B_2S---B---\n", info->type);
usleep(DEALY_2S);
}
break;
case PRINT_A_B_250MS:
while (*info->state == PRINT_A_B_250MS) {
LOGI("type:%d PRINT_A_B_250MS---A---\n", info->type);
usleep(DELAY_250MS);
LOGI("type:%d PRINT_A_B_250MS---B---\n", info->type);
usleep(DELAY_250MS);
}
break;
default:
break;
}
usleep(DELAY_1S);
}
return (void *)0;
}
int main(int argc, char *argv[])
{
unsigned int i = 0;
int semId;
int shmId;
int ret = 0;
ShmInfoHandle *info = NULL;
pthread_t printThread[3];
ret = IPC_SemShmIdInit(&semId, &shmId);
if (ret != 0) {
LOGE("call IPC_SamShaIdInit failed.");
return -1;
}
info = (ShmInfoHandle *)shmat(shmId, NULL, 0);
if (info == (void *)-1) {
LOGE("Get shm Addr failed. err:%s\n", strerror(errno));
goto destory;
}
memset(info, 0, sizeof(ShmInfoHandle));
for (i = 0; i < 3; i++) {
ret = pthread_create(&printThread[i], NULL, PrintThreadFunc, (PrintThreadInfoHandle *)&g_printThreadInfo[i]);
if (ret < 0) {
LOGE("Create Thread failed. err:%s i:%d\n", strerror(errno), i);
goto destory;
}
}
while (1) {
IPC_SemaphoreCtrl(semId, SEM_CTRL_P);
*g_printThreadInfo[info->type].state = info->state;
LOGI("PrintState Change successful. type:%d state:%d\n", info->type, *g_printThreadInfo[info->type].state);
}
destory:
IPC_DestorySemShm(semId, shmId);
return -1;
}
进程2
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include "interface.h"
#define INPUT_PARAMETER_NUMS (3)
#define INPUT_PARAMETER_TYPE_PRINT_TYPE (1)
#define INPUT_PARAMETER_TYPE_PRINT_STATE (2)
int main(int argc, char *argv[])
{
if (argc != INPUT_PARAMETER_NUMS) {
LOGE("arg failed.[0.file 1.type 2.state]\n");
return 0;
}
int type = atoi(argv[INPUT_PARAMETER_TYPE_PRINT_TYPE]);
int state = atoi(argv[INPUT_PARAMETER_TYPE_PRINT_STATE]);
ChangePrintState(type, state);
return 0;
}