mmap实现共享内存,采用信号量同步

56 篇文章 2 订阅

服务端将数据发送到共享内存段:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>
#include<stdint.h>
#include<stdatomic.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include<time.h>

#include"../persistence.h"

#define SEMKEYPATH "/dev/null" /**< Path used on ftok for semget key */
#define SEMKEYID   1
#define NUMSEMS    2
#define SHMPATH    "/tmp/rpc_server"

int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
		       const struct timespec *timeout);

typedef struct image {
	int seq_num;
	char name[20];
	size_t size;
	uint8_t data[0];
}Image;

typedef struct rpc_server {
	int32_t semid;
	void* shm_addr;
	size_t size;
	struct sembuf operations[2];
}RPCServer;

RPCServer* construct_rpc_server(size_t size)
{
	int32_t semid, rc;
	key_t semkey;
	int16_t sarray[NUMSEMS];

	RPCServer* pthis = (RPCServer *)malloc(sizeof(*pthis));
	if (!pthis)
		return NULL;

	/**
	 * Create an IPC key for the semaphore set.
	 */
	semkey = ftok(SEMKEYPATH, SEMKEYID);
	if (semkey == (key_t)-1) {
		perror("ftok");
		goto free;
	}

	/**
	 * Create a semphore set using the IPC key. The number of
	 * semphores in the set is two. If a semphore set already
	 * exists for the key, return an error. The specified permission give everyone read/write access to the semphore set.
	 */
	semid = semget(semkey, NUMSEMS, 0666 | IPC_CREAT | IPC_EXCL);
	if (semid == -1) {
		perror("semget");
		goto free;
	}
	pthis->semid = semid;

	/**
	 * Initialize the first semphore and the second semaphore
	 * int the set to 0.
	 *
	 * The first semaphore in the sem set means:
	 *	'1' -- The shared memory segment is being used.
	 *	'0' -- The shared memory segment is freed.
	 * The second semaphore in the sem set means:
	 *  '1' -- The shared memory segment has been changed by 
	 *         the server.
	 *  '0' -- The shared memory segment has not been changed
	 *         by the server.
	 */
	sarray[0] = 0; 
	sarray[1] = 0;

	rc = semctl(semid, 0, SETALL, sarray);
	if (rc == -1) {
		perror("semctl");
		goto free;
	}

	int fd = open(SHMPATH, O_RDWR|O_CREAT|O_TRUNC, 0644);
	if (fd < 0) {
		perror("open");
		goto free;
	}
	ftruncate(fd, size); 

	pthis->size = size;	
	pthis->shm_addr = mmap(NULL, size, 
			               PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 
	if (pthis->shm_addr == MAP_FAILED) {
		perror("mmap");
		close(fd);
		goto free;
	}
	close(fd); 

	return pthis;

free:
	free(pthis);

	return NULL;
}

int rpc_send(RPCServer* pthis, void* data, size_t size)
{
	int ret, rc;
	static uint32_t next = 1;
	struct sembuf operations[2];
	const struct timespec timeout = {.tv_sec = 10UL, .tv_nsec = 0UL};
	union semun {
		int val;
		struct semid_ds *buf;
		ushort *array;
	} arg;
	ret = semctl(pthis->semid, 1, GETVAL, arg);

	operations[0].sem_num = 1;
	operations[0].sem_op =  0;
	operations[0].sem_flg = 0;

	operations[1].sem_num = 0;
	operations[1].sem_op = 1;
	operations[1].sem_flg = 0;

	rc = semtimedop(pthis->semid, operations, (size_t)2, &timeout);
	if (rc == -1) {
		perror("semop");
		return -1;
	}
	memcpy(pthis->shm_addr, data, size);
	printf("fanout: %d\n", next++);

	operations[0].sem_num = 0;
	operations[0].sem_op = -1;
	operations[0].sem_flg = 0;

	operations[1].sem_num = 1;
	operations[1].sem_op = 2;
	operations[1].sem_flg = 0;

	rc = semop(pthis->semid, operations, 2);
	if (rc == -1) {
		perror("semop");
		return -1;
	}

	return 0;
}

void destroy_ipc_server(RPCServer **ppthis)
{
	int32_t ret, rc;
	if (!ppthis) return;
	if (!*ppthis) return;

    ret = semctl((*ppthis)->semid, 1, IPC_RMID);
	if (rc == -1) {
		perror("semctl");
	}

	ret = munmap((*ppthis)->shm_addr, (*ppthis)->size);
	if (ret < 0) {
		perror("munmap");
	}

	free(*ppthis);
	*ppthis = NULL;

	return;
}

int main()
{
	size_t size;
	uint8_t* data;

	read_jpg_file("./test.jpg", &data, &size);
	size = size + sizeof(Image);
	
	RPCServer* pthis = construct_rpc_server(size);

	Image* img = (Image*)malloc(size);
	memset(img, 0, sizeof(*img));
	memcpy(img->data, data, size);
	img->size = size;
	strcpy(img->name, "xxdk");

	int total = 100;
	while(total--) {
		usleep(1000*20);
		img->seq_num++;
		rpc_send(pthis, img, size);
	}

	sleep(1);
	destroy_ipc_server(&pthis);

	return 0;
}


客户端读取服务端的数据跟新:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<stdint.h>
#include<string.h>
#include<stdatomic.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include"../persistence.h"

#define SEMKEYPATH "/dev/null"
#define SEMKEYID   1
#define NUMSEMS    2
#define SHMPATH    "/tmp/rpc_server"

typedef struct image {
	int seq_num;
	char name[20];
	size_t size;
	uint8_t data[0];
}Image;

typedef struct rpc_client {
	int32_t semid;
	void* shm_addr;
	size_t size;
	struct sembuf operations[2];
}RPCClient;

RPCClient* construct_rpc_client(size_t size)
{
	key_t semkey;
	int32_t semid, rc;
	RPCClient* pthis = (RPCClient*)malloc(sizeof(*pthis));
	if (!pthis)
		return NULL;

	semkey = ftok(SEMKEYPATH, SEMKEYID);
	if (semkey == (key_t)-1) {
		perror("ftok");
		goto free;
	}

	pthis->semid = semget(semkey, NUMSEMS, 0666);
	if (pthis->semid == -1) {
		perror("semget");
		goto free;
	}

	int fd = open(SHMPATH, O_RDWR, 0644);
	if (fd < 0) {
		perror("open");
		goto free;
	}
	ftruncate(fd, size);

	pthis->size = size;	
	pthis->shm_addr = mmap(NULL, size, 
		                   PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if (pthis->shm_addr == MAP_FAILED) {
		perror("mmap");
		close(fd);
		goto free;
	}
	close(fd);

	return pthis;
free:
	free(pthis);
	return NULL;
}

int rpc_recv(RPCClient* pthis)
{
	int rc;
	char name[32] = {0};
	struct sembuf operations[2];

	operations[0].sem_num = 1;
	operations[0].sem_op =  -1;
	operations[0].sem_flg = 0;

	operations[1].sem_num = 0;
	operations[1].sem_op =  1;
	operations[1].sem_flg = IPC_NOWAIT|SEM_UNDO;
	rc = semop(pthis->semid, operations, 1);
	if (rc == -1) {
		perror("semop");
		return -1;
	}

	Image* p = (Image *)pthis->shm_addr;
	printf("seq_num = %d, name = %s, size = %ld\n", 
			p->seq_num, p->name, p->size);	
	sprintf(name, "./image/%d.jpg", p->seq_num);
	//write_jpg_file(name, p->data, p->size);

	operations[0].sem_num = 0;
	operations[0].sem_op = -1;
	operations[0].sem_flg = IPC_NOWAIT;

	operations[0].sem_num = 1;
	operations[0].sem_op =  -1;
	operations[0].sem_flg = 0;
	rc = semop(pthis->semid, operations, 2);
	if (rc == -1) {
		perror("semop");
		return -1;
	}

	return 0;
}

void destroy_ipc_client(RPCClient** ppthis)
{
	if (!ppthis) return;
	if (!*ppthis) return;
	
	int ret = munmap((*ppthis)->shm_addr, (*ppthis)->size);
	if (ret < 0) {
		perror("munmap");
		exit(4);
	}
	free(*ppthis);
	*ppthis = NULL;

	return;
}

int main()
{
	RPCClient* pthis = construct_rpc_client(5*1024*1024);

	while (1) {
		if (rpc_recv(pthis) < 0)
			break;
	}

	destroy_ipc_client(&pthis);

	return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 POSIX 信号量的 C 语言代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> #include <semaphore.h> #define SHM_SIZE 1024 int main() { int shm_fd; char *shm_ptr; sem_t *sem_ptr; // 打开共享内存 shm_fd = shm_open("/myshm", O_RDWR | O_CREAT, 0666); if (shm_fd == -1) { perror("shm_open failed"); return 1; } // 设置共享内存大小 if (ftruncate(shm_fd, SHM_SIZE) == -1) { perror("ftruncate failed"); return 1; } // 映射共享内存到进程地址空间 shm_ptr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (shm_ptr == MAP_FAILED) { perror("mmap failed"); return 1; } // 创建信号量 sem_ptr = sem_open("/mysem", O_CREAT, 0666, 1); if (sem_ptr == SEM_FAILED) { perror("sem_open failed"); return 1; } // 循环读写共享内存 for (int i = 0; i < 10; i++) { // 加锁 if (sem_wait(sem_ptr) == -1) { perror("sem_wait failed"); return 1; } // 写入数据 snprintf(shm_ptr, SHM_SIZE, "Hello, world! %d", i); // 解锁 if (sem_post(sem_ptr) == -1) { perror("sem_post failed"); return 1; } // 加锁 if (sem_wait(sem_ptr) == -1) { perror("sem_wait failed"); return 1; } // 读取数据 printf("shm_ptr = %s\n", shm_ptr); // 解锁 if (sem_post(sem_ptr) == -1) { perror("sem_post failed"); return 1; } // 等待 1 秒 sleep(1); } // 关闭共享内存 if (munmap(shm_ptr, SHM_SIZE) == -1) { perror("munmap failed"); return 1; } if (shm_unlink("/myshm") == -1) { perror("shm_unlink failed"); return 1; } // 关闭信号量 if (sem_close(sem_ptr) == -1) { perror("sem_close failed"); return 1; } if (sem_unlink("/mysem") == -1) { perror("sem_unlink failed"); return 1; } return 0; } ``` 这个示例程序创建了一个大小为 1024 字节的共享内存区域和一个名为 "/mysem" 的信号量,然后在一个循环中往共享内存中写入数据,并从共享内存中读取数据。在写入和读取共享内存之前,分别使用 `sem_wait()` 和 `sem_post()` 函数对信号量进行加锁和解锁,以确保多个进程或线程之间的同步和互斥。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值