最近在学习Linux进程间的通信。写了一段代码,加深学习印象
1、信号量操作的封装
//sem_com.c
#include "sem_com.h"
//初始化信号量
int init_sem(int sem_id, int init_value)
{
union semun sem_union;
sem_union.val = init_value;
if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
{
perror("init_sem fail!");
return -1;
}
return 0;
}
//删除信号量
int del_sem(int sem_id)
{
union semun sem_union;
if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
{
perror("del_sem fail!");
return -1;
}
return 0;
}
//P操作
int sem_p(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
perror("sem_p fail!");
return -1;
}
return 1;
}
//V操作
int sem_v(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
perror("sem_v fail!");
return -1;
}
return 1;
}
//sem_com.h
#ifndef _SEM_COM_H_
#define _SEM_COM_H_
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
//初始化信号量
int init_sem(int sem_id, int init_value);
//删除信号量
int del_sem(int sem_id);
//P操作
int sem_p(int sem_id);
//V操作
int sem_v(int sem_id);
#endif
2、发送端
//commun_server.c
#include "communition.h"
#include "sem_com.h"
//#include "date_type.h"
void ignor_signal(void);
int main(int argc, char *argv[])
{
key_t key;
int sem_id = 0;
int shm_id = 0;
void *shm_addr = NULL;
SHM_DATE_TYPE shm_data = {0};
char quit_flag[] = "quit";
// 忽略一些系统信号
// ignor_signal();
//信号量的处理
if((key = ftok(".", 'a')) == -1)
{
error_callback("ftok fail!");
}
if((sem_id = semget(key, 1, 0666|IPC_CREAT)) == -1)
{
error_callback("semget fail");
}else
{
printf("sem_id:%d \n", sem_id);
init_sem(sem_id, 1);
}
//共享内存的处理
if((shm_id = shmget(key, sizeof(SHM_DATE_TYPE), IPC_CREAT|0666)) == -1)
{
printf("11111111111111");
del_sem(sem_id);
error_callback("shmget fail");
}else
{
shm_addr = shmat(shm_id, (void *)0, 0);
if((void *)-1 == shm_addr)
{
printf("22222222222");
del_sem(sem_id);
error_callback("shmat fail");
}
}
printf("shmat addr:%x\n",(int)shm_addr);
do
{
printf("\ninput some message: ");
//抢占资源P操作
if(sem_p(sem_id) == -1)
{
exit(1);
}
shm_data.pid = getpid();
memset(shm_data.buffer, 0, sizeof(shm_data.buffer));
if(fgets(shm_data.buffer, SHM_BUFFER_SIZE, stdin) == NULL)
{
del_sem(sem_id);
error_callback("user input fail");
}
strncpy(shm_addr, shm_data.buffer, strlen(shm_data.buffer));
//释放占用的资源V操作
if(sem_v(sem_id) == -1)
{
exit(1);
}
printf("shm_data.buffer:%s\n", shm_data.buffer);
}while((strncmp(shm_data.buffer, quit_flag, strlen(quit_flag))));
del_sem(sem_id);
if(shmdt(shm_addr) == -1)
{
error_callback("shmdt fail");
}
exit(0);
}
void ignor_signal(void)
{
signal(SIGSTOP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
}
3、接收端
//commun_client.c
#include "communition.h"
#include "sem_com.h"
//#include "date_type.h"
void ignor_signal(void);
int main(int argc, char *argv[])
{
key_t key;
int sem_id = 0;
int shm_id = 0;
void *shm_addr = NULL;
SHM_DATE_TYPE shm_data = {0};
char quit_flag[] = "quit";
// 忽略一些系统信号
// ignor_signal();
//信号量的处理
if((key = ftok(".", 'a')) == -1)
{
error_callback("ftok fail!");
}
if((sem_id = semget(key, 1, 0666)) == -1)
{
error_callback("semget fail");
}else
{
printf("sem_id:%d \n", sem_id);
//init_sem(sem_id, 1);
}
//共享内存的处理
if((shm_id = shmget(key, sizeof(SHM_DATE_TYPE), IPC_CREAT|0666)) == -1)
{
printf("11111111111111");
del_sem(sem_id);
error_callback("shmget fail");
}else
{
shm_addr = shmat(shm_id, (void *)0, 0);
if((void *)-1 == shm_addr)
{
printf("22222222222");
del_sem(sem_id);
error_callback("shmat fail");
}
}
printf("shmat addr:%x\n",(int)shm_addr);
do
{
if(sem_p(sem_id) == -1)
{
exit(1);
}
shm_data.pid = getpid();
memset(shm_data.buffer, 0, sizeof(shm_data.buffer));
strncpy(shm_data.buffer, shm_addr, strlen(shm_addr));
printf("shm_data.buffer len:%d\n", strlen(shm_addr));
//memcpy(shm_data, shm_addr, sizeof(SHM_BUFFER_SIZE));
//释放占用的资源V操作
//把内存中的数据读完之后,数据还是存在的,需要把数据在清除掉
memset(shm_addr, 0, strlen(shm_addr));
if(sem_v(sem_id) == -1)
{
del_sem(sem_id);
shmdt(shm_id);
exit(1);
}
printf("get shmbuf some::%s\n", shm_data.buffer);
}while((strncmp(shm_data.buffer, quit_flag, strlen(quit_flag))));
del_sem(sem_id);
if(shmdt(shm_addr) == -1)
{
error_callback("shmdt fail");
}
exit(0);
}
void ignor_signal(void)
{
signal(SIGSTOP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
}
//communtion.h
#ifndef __COMMUNITION_H__
#define __COMMUNITION_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#include <signal.h>
#include "date_type.h"
void error_callback(char *err_msg);
typedef struct
{
int pid;
char buffer[SHM_BUFFER_SIZE];
}SHM_DATE_TYPE;
#endif //__COMMUNITION_H__
总结:
1、信号量可以理解为是一个全局的变量,他的值就是资源。被占用了,资源-1,释放了,资源+1。
2、当P操作,没有可用资源时,会一直阻塞。
3、只要创建信号量的semget使用的key是一样的,那就是代表同一个信号量,这个KEY可以是认为这个信号量的钥匙吗?
4、共享内存,把一段内核空间的内存映射在进程中。读端在读取数据后,下次读取发现尾部还残留了上次的数据。每次读取完毕之后memset没有复现此问题。应该是读取数据之后并不会清除掉,要手动清除。