Linux共享内存与信号量

最近在学习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没有复现此问题。应该是读取数据之后并不会清除掉,要手动清除。

发布了22 篇原创文章 · 获赞 9 · 访问量 8825

猜你喜欢

转载自blog.csdn.net/ljm_c_bok/article/details/88777363
今日推荐