使用訊號量進行同步的共享記憶體機制
一、簡介
共享記憶體為在多個程式之間共享和傳遞資料提供了一種有效的方式。
但它本身並未提供同步機制。
在實際程式設計中,可以使用
訊號量,
傳遞訊息(使用管道或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);
- }
三、消費者程式
消費者程式的基本流程:
開啟輸出檔案並初始化幀;
獲取共享記憶體和訊號量;
每次
得到共享記憶體的許可權後,
從共享記憶體中讀取一幀並獲得結束標誌
進行幀處理,
釋放共享記憶體的許可權。
直到結束標誌為真。
最後釋放相關的資源。
consumer.c
- /*
- * \File
- * consumer.c
- * \Brief
- *
- */
- #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_out = 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;
- int end_flag = 0;
- /* Open output file */
- if ((fp_out = fopen(OUTPUT_FILE, "wb")) < 0 )
- {
- printf("Open output file failed: %s\n", OUTPUT_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 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;
- printf("FRAME_CNT: %d\n", frame_cnt);
- /*
- * 必須先置0,
- * 否則會因生產者程式的異常退出未釋放訊號量而導致程式出錯
- */
- set_semvalue(sem_id, 0);
- do
- {
- semaphore_p(sem_id);
- /* Read frame from shared-memory */
- read_frame_from_shm(&frame, shared_stuff);
- end_flag = shared_stuff->end_flag;
- crop_frame(&frame, 10, 10, 40, 40);
- write_frame_into_file(fp_out, &frame);
- semaphore_v(sem_id);
- frame_cnt++;
- printf("FRAME_CNT: %d\n", frame_cnt);
- } while(!end_flag);
- /* Over */
- printf("\nConsumer over!\n");
- fclose(fp_out);
- free_frame(&frame);
- if (shmdt(shared_memory) == -1)
- {
- fprintf(stderr, "shmdt failed.\n");
- exit(EXIT_FAILURE);
- }
- exit(EXIT_SUCCESS);
- }
四、訊號量函式和幀處理函式
訊號量函式
semaphore.c
- /*
- * \File
- * semaphore.c
- * \Breif
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/sem.h>
- #include "semaphore.h"
- /* init semaphore by semctl */
- int set_semvalue(int sem_id, int value)
- {
- union semun sem_union;
- sem_union.val = value;
- if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
- return 1;
- return 0;
- }
- /* delete semaphore by sectl */
- void del_semvalue(int sem_id)
- {
- union semun sem_union;
- if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
- fprintf(stderr, "Failed to delete semaphore\n");
- }
- /* P(v) */
- int semaphore_p(int sem_id)
- {
- struct sembuf sem_b;
- sem_b.sem_num = 0;
- sem_b.sem_op = -1; /* P(v) */
- sem_b.sem_flg = SEM_UNDO;
- if (semop(sem_id, &sem_b, 1) == -1)
- {
- fprintf(stderr, "semaphore_p failed\n");
- return 1;
- }
- return 0;
- }
- /* V(v) */
- int semaphore_v(int sem_id)
- {
- struct sembuf sem_b;
- sem_b.sem_num = 0;
- sem_b.sem_op = 1; // V(v)
- sem_b.sem_flg = SEM_UNDO;
- if (semop(sem_id, &sem_b, 1) == -1)
- {
- fprintf(stderr, "semaphore_v failed\n");
- return 1;
- }
- return 0;
- }
幀處理函式
frame.c
- /*
- * \File
- * frame.c
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <memory.h>
- #include <assert.h>
- #include <errno.h>
- #include "frame.h"
- /*
- * \Brief
- * init frame
- */
- int init_frame(frame_p frame, int width, int height, frame_type_e type)
- {
- assert(frame != NULL);
- frame->frm_w = width;
- frame->frm_h = height;
- frame->frm_type = type;
- switch(frame->frm_type)
- {
- case YUV420:
- frame->frm_size = (frame->frm_w * frame->frm_h * 3) / 2;
- break;
- case YUV422:
- frame->frm_size = frame->frm_w * frame->frm_h * 2;
- break;
- case YUV444:
- frame->frm_size = frame->frm_w * frame->frm_h * 3;
- break;
- case RGB:
- frame->frm_size = frame->frm_w * frame->frm_h * 3;
- break;
- default:
- fprintf(stderr, "frame type is invalid.");
- return 1;
- }
- if ((frame->frm_comps = (char*)calloc(frame->frm_size, sizeof(char))) == NULL)
- {
- fprintf(stderr, "calloc failed.");
- return 1;
- }
- return 0;
- }
- /*
- * \Brief
- * init frame
- */
- int free_frame(frame_p frame)
- {
- assert(frame != NULL);
- free(frame->frm_comps);
- return 0;
- }
- /*
- * \Brief
- * read a frame from file
- */
- int read_frame_from_file(frame_p frame, FILE* fp)
- {
- int ret;
- assert(frame != NULL && fp != NULL);
- if (ret = (fread(frame->frm_comps, sizeof(char), frame->frm_size, fp))
- != frame->frm_size)
- {
- fprintf(stderr, "read_frame_from_file failed. %d\n", ret);
- return 1;
- }
- return 0;
- }
- /*
- * \Brief
- * write a frame into file
- */
- int write_frame_into_file(FILE* fp, frame_p frame)
- {
- assert(frame != NULL && fp != NULL);
- if (fwrite(frame->frm_comps, sizeof(char), frame->frm_size, fp)
- != frame->frm_size)
- {
- fprintf(stderr, "write_frame_into_file failed.\n");
- return 1;
- }
- return 0;
- }
- /*
- * \Brief
- * read a frame from shared-memory
- */
- int read_frame_from_shm(frame_p frame, shared_use_st* shm)
- {
- assert(frame != NULL && shm != NULL);
- memcpy((char*)frame->frm_comps, (char*)shm->shm_sp, frame->frm_size);
- return 0;
- }
- /*
- * \Brief
- * write a frame into shared-memory
- */
- int write_frame_into_shm(shared_use_st* shm, frame_p frame)
- {
- assert(frame != NULL && shm != NULL);
- memcpy((char*)shm->shm_sp, (char*)frame->frm_comps, frame->frm_size);
- return 0;
- }
- /*
- * \Brief
- * crop frame
- */
- int crop_frame(frame_p frame, int l_offset, int t_offset, int c_w, int c_h)
- {
- char* crop_loc;
- int index_h;
- assert(frame != NULL);
- if ((l_offset + c_w) > frame->frm_w)
- {
- printf("Crop width is out of range.\n");
- return 1;
- }
- if ((t_offset + c_h) > frame->frm_h)
- {
- printf("Crop height is out of range.\n");
- return 1;
- }
- crop_loc = frame->frm_comps + (t_offset * frame->frm_w) + l_offset;
- for (index_h = 0; index_h < c_h; index_h++)
- {
- memset(crop_loc, PIX_VALUE, c_w);
- crop_loc += frame->frm_w;
- }
- return 0;
- }
五、編譯與執行
makefile.producer
- OBJECTS = producer.o semaphore.o frame.o
- CC = gcc
- CFLAG = -g -Wa
- producer : $(OBJECTS)
- $(CC) $(CFLAG) -o producer $(OBJECTS)
- producer.o: common.h semaphore.h frame.h shm_com.h
- semaphore.o:semaphore.h
- frame.o: frame.h
- .PHONY:clean
- clean:
- rm producer $(OBJECTS)
makefile.consumer
- OBJECTS = consumer.o semaphore.o frame.o
- CC = gcc
- CFLAG = -g -Wa
- consumer : $(OBJECTS)
- $(CC) $(CFLAG) -o consumer $(OBJECTS)
- consumer.o: common.h semaphore.h frame.h shm_com.h
- semaphore.o:semaphore.h
- frame.o:frame.h
- .PHONY:clean
- clean:
- rm consumer $(OBJECTS)
編譯與執行:
- $make -f makefile.producer
- $make -f makefile.consumer
- $producer &
- $consumer
轉自 http://blog.chinaunix.net/uid-26000296-id-3442827.html
相關文章
- 程式間通訊機制(管道、訊號、共享記憶體/訊號量/訊息佇列)、執行緒間通訊機制(互斥鎖、條件變數、posix匿名訊號量)記憶體佇列執行緒變數
- 訊號量、訊息佇列、共享記憶體複習佇列記憶體
- 執行緒通訊機制:共享記憶體 VS 訊息傳遞執行緒記憶體
- 又是訊號量和共享記憶體沒有釋放的db待機記憶體
- 程式間通訊——基於共享記憶體和訊號量實現共享佇列記憶體佇列
- ORACLE在各作業系統訊號量與共享記憶體的維護Oracle作業系統記憶體
- oracle中的共享記憶體和訊號量的一個簡單解釋Oracle記憶體
- 多程式之間的執行緒利用XSI IPC共享記憶體分配互斥量進行同步執行緒記憶體
- 唯快不破:【多執行緒】使用訊號量進行同步執行緒
- 建立程序,設計訊號量同步機制,實現多執行緒同步 - C語言版執行緒C語言
- Java程式執行記憶體機制Java記憶體
- Linux程式間通訊——使用共享記憶體Linux記憶體
- 2.3.2 訊號量機制——作業系統筆記作業系統筆記
- 程式間通訊---共享記憶體記憶體
- nginx中共享記憶體的使用Nginx記憶體
- Handler 訊息機制以及記憶體洩漏記憶體
- windows多執行緒同步--訊號量Windows執行緒
- C# .Net 多程式同步 通訊 共享記憶體 記憶體對映檔案 Memory MappedC#記憶體APP
- JavaScript 記憶體機制JavaScript記憶體
- Java的記憶體回收機制Java記憶體
- 程式間通訊之共享記憶體記憶體
- 程序間通訊(3)-共享記憶體記憶體
- 執行緒同步(windows平臺):訊號量執行緒Windows
- iOS多執行緒非同步訊號量iOS執行緒非同步
- 共享記憶體記憶體
- 作為phper既然瞭解共享記憶體函式shmop的使用方法,那麼就必須要了解一下訊號量是什麼,以及訊號量使用的程式碼案例PHP記憶體函式
- js記憶體回收機制JS記憶體
- javaScript 記憶體管理機制JavaScript記憶體
- Java記憶體管理機制Java記憶體
- 【AIX】AIX記憶體機制AI記憶體
- linux記憶體機制Linux記憶體
- Qt 記憶體管理機制QT記憶體
- jvm記憶體管理機制JVM記憶體
- system-v IPC共享記憶體通訊記憶體
- 記憶體管理機制的發展記憶體
- 關於JavaScript的記憶體機制JavaScript記憶體
- JavaScript 記憶體機制(前端同學進階必備)JavaScript記憶體前端
- linux程式間的通訊(C): 共享記憶體Linux記憶體