条件变量放在共享内存中可以进程间同步吗

条件变量放在共享内存中可以进程间同步吗,第1张

一、简介

共享内存为在多个进程之间共享和传递数据提供了一种有效的方式。

但它本身并未提供同步机制。

在实际编程中,可以使用

信号量

传递消息(使用管道或IPC消息),

生成信号,

条件变量,

等方法来提供读写之间的有效的同步机制。

本例程序使用信号量进行同步,

主要是因为它方便,使用广泛,且独立于进程。

本例程序实现了,

生产者进程:

每次读取YUV输入文件的一帧,

然后将其写到共享内存中。

消费者进程:

每次从共享内存中读到一帧,

处理后,

将其写到输出文件。

两个进程间使用信号量来保证同步处理每一帧。

本例程序很好地示范了共享内存和信号量的机制,

对于实际程序的开发很有意义。

二、生产者进程

common.h

用来设置一些测试用的基本参数。

/*

* \File

* common.h

*/

#ifndef __COMMON_H__

#define __COMMON_H__

#define TEST_FILE "coastguard_cif.yuv"

#define OUTPUT_FILE "coastguard_cif_trsd.yuv"

#define FYUV_WIDTH 352

#define FYUV_HEIGHT 288

#endif

共享内存相关的头文件。

shm_com.h

/*

* \File

* shm_com.h

* \Brief

*/

#ifndef __SHM_COM_H__

#define __SHM_COM_H__

#define SHM_SEED 1001

#define MAX_SHM_SIZE 2048*2048*3

typedef struct shared_use_st

{

int end_flag //用来标记进程间的内存共享是否结束: 0, 未结束; 1, 结束

char shm_sp[MAX_SHM_SIZE]//共享内存的空间

}shared_use_st

#endif

信号量的头文件

semaphore.h

/*

* \File

* semaphore.h

* \Brief

* semaphore operation

*/

#ifndef __SEMAPHORE_H__

#define __SEMAPHORE_H__

#define SEM_SEED 1000

union semun

{

int val

struct semid_ds *buf

unsigned short *array

}

int set_semvalue(int sem_id, int value)

void del_semvalue(int sem_id)

int semaphore_p(int sem_id)

int semaphore_v(int sem_id)

#endif

帧处理的头文件

frame.h

/*

* \File

* frame.h

* \Brief

*

*/

#ifndef __FRAME_H__

#define __FRAME_H__

#include "shm_com.h"

#define PIX_VALUE 1

typedef enum

{

YUV420,

YUV422,

YUV444,

RGB

}frame_type_e

typedef struct

{

int frm_w// width

int frm_h// height

frame_type_e frm_type

int frm_size

char *frm_comps

}frame_t, *frame_p

int init_frame(frame_p frame, int width, int height, frame_type_e type)

int free_frame(frame_p frame)

int read_frame_from_file(frame_p frame, FILE* fp)

int write_frame_into_file(FILE* fp, frame_p frame)

int read_frame_from_shm(frame_p frame, shared_use_st* shm)

int write_frame_into_shm(shared_use_st* shm, frame_p frame)

int crop_frame(frame_p frame, int l_offset, int t_offset, int c_w, int c_h)

#endif

生产者进程的基本流程:

打开输入文件并初始化帧

创建并初始化共享内存和信号量

然后每次读取一帧,

用信号量获取共享内存的权限后,

将读取的帧写入共享内存,

再释放共享内存的权限。

当处理完所有的帧后,

设置结束标志,

并释放相关的资源。

producer.c

/*

* \File

* producer.c

* \Brief

* Test shared-memory and message-queue

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <unistd.h>

#include <sys/shm.h>

#include <sys/sem.h>

#include "common.h"

#include "semaphore.h"

#include "shm_com.h"

#include "frame.h"

int main(char argc, char* argv[])

{

FILE* fp_in = NULL

frame_t frame

int frame_cnt = 0

int sem_id// semaphore id

int shm_id// shared-memory id

void* shared_memory = (void*)0

shared_use_st* shared_stuff

/* Open input file */

if ((fp_in = fopen(TEST_FILE, "rb")) <0 )

{

printf("Open input file failed: %s\n", TEST_FILE)

exit(EXIT_FAILURE)

}

/* Init frame */

init_frame(&frame, FYUV_WIDTH, FYUV_HEIGHT, YUV420)

printf("FRAME: w = %d, h = %d\n", frame.frm_w, frame.frm_h)

/* Create and init semaphore */

sem_id = semget((key_t)SEM_SEED, 1, 0666 | IPC_CREAT)

if (sem_id == -1)

{

fprintf(stderr, "semget failed.\n")

exit(EXIT_FAILURE)

}

/* Init shared-memory */

shm_id = shmget((key_t)SHM_SEED, sizeof(struct shared_use_st), 0666 | IPC_CREAT)

if (shm_id == -1)

{

fprintf(stderr, "shmget failed.\n")

exit(EXIT_FAILURE)

}

shared_memory = shmat(shm_id, (void*)0, 0)

if (shared_memory == (void*)-1)

{

fprintf(stderr, "shmat failed.\n")

exit(EXIT_FAILURE)

}

shared_stuff = (struct shared_use_st*)shared_memory

shared_stuff->end_flag = 0

printf("FRAME_CNT: %d\n", frame_cnt)

set_semvalue(sem_id, 1)

while (read_frame_from_file(&frame, fp_in) == 0)

{

semaphore_p(sem_id)

/* Write it into shared memory */

write_frame_into_shm(shared_stuff, &frame)

shared_stuff->end_flag = 0

semaphore_v(sem_id)

frame_cnt++

printf("FRAME_CNT: %d\n", frame_cnt)

}

semaphore_p(sem_id)

shared_stuff->end_flag = 1

semaphore_v(sem_id)

/* over */

printf("\nProducer over!\n")

fclose(fp_in)

free_frame(&frame)

del_semvalue(sem_id)

if (shmdt(shared_memory) == -1)

{

fprintf(stderr, "shmdt failed.\n")

exit(EXIT_FAILURE)

}

exit(EXIT_SUCCESS)

}

信号量在进程是以有名信号量进行通信的,在线程是以无名信号进行通信的,因为线程linux还没有实现进程间的通信,所以在sem_init的第二个参数要为0,而且在多线程间的同步是可以通过有名信号量也可通过无名信号,但是一般情况线程的同步是无名信号量,无名信号量使用简单,而且sem_t存储在进程空间中,有名信号量必须LINUX内核管理,由内核结构struct ipc_ids 存储,是随内核持续的,系统关闭,信号量则删除,当然也可以显示删除,通过系统调用删除,

消息队列,信号量,内存共享,这几个都是一样的原理。,只不过信号量分为有名与无名

无名使用 <semaphore.h>,

有名信号量<sys/sem.h>

无名信号量不能用进程间通信,

//无名与有名的区别,有名需要KEY值与IPC标识

所以sem_init的第二个参数必须为0,,,,

你好。

不只是sem.h,很多头文件都有/usr/include/linux和/usr/include/sys两个版本。

我的印象是:linux目录里面的头文件用于内核,

sys目录里面的头文件用于应用程序或者glibc标准库


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/81344.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-04
下一篇2023-03-04

发表评论

登录后才能评论

评论列表(0条)

    保存