1. 程式人生 > >多程序+共享記憶體+訊號量綜合例項

多程序+共享記憶體+訊號量綜合例項

測試框架

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>

#include "myipc_sem.h"
#include "myipc_shm.h"

void Test(int var)
{

  int cnt = 0
; int ret = 0; int shmdl = 0; int *addr = NULL; key_t key ; int semid = 0; //利用獲取的key開啟/建立訊號量集合 key = ftok("./",'a'); //建立訊號量集合--預設建立1個訊號量 ret = sem_open(key, &semid); if(ret == SEMERR_ENOXIST) { ret = sem_create(key, &semid); if(ret != 0) { printf("sem_create err\n"
); return -1; } } //sem_p(semid);//p操作 printf("Aloha!Fork()....%d\n",var); ret = IPC_CreatShm("./", sizeof(int), &shmdl); if(ret != 0) { printf("IPC_CreatShm err\n"); return -1; } ret = IPC_MapShm(shmdl,(void**)&addr); cnt = ++(*addr); printf
("cnt:%d\n",cnt); ret = IPC_UnMapShm(addr);//顯示解除對映關係 //sem_v(semid);//v操作 printf("child: %d exit!\n=================================================================\n",getpid()); } int main() { int loop_num = 0; int proc_num = 0; int i = 0,j = 0; pid_t pid ; int ret = 0; int shmdl = 0; key_t key = 0; int semid = 0; signal(SIGCHLD,SIG_IGN); printf("Input the procnum:\n"); scanf("%d",&proc_num); printf("Input the loopnum:\n"); scanf("%d",&loop_num); //建立共享記憶體--父程序建立的時候使用的key和子程序一樣, //所以即使在子程序再次建立,實則是獲取已存在的共享記憶體--所以是同一塊共享記憶體 //當然可以在子程序裡面不再重新呼叫建立共享記憶體的函式(實際上也沒有真的建立) //可以通過向子程序傳遞已經建立好的共享記憶體ID--讓他對映到自己的記憶體空間 //就算父程序沒有建立,眾多子程序建立了,只要key一樣--就是同一塊共享記憶體 ret = IPC_CreatShm("./", sizeof(int), &shmdl); if(ret != 0) { printf("IPC_CreatShm err\n"); return -1; } //利用獲取的key開啟/建立訊號量集合 key = ftok("./",'a'); //建立訊號量集合--預設建立1個訊號量 //儘管子程序再次呼叫該部分程式碼--表面上重新建立訊號量 //但由於key相同,系統裡面已經有父程序建立的訊號量,所以他們是同一個訊號量集合 //原理和父子程序建立共享記憶體一樣 ret = sem_open(key, &semid); if(ret == SEMERR_ENOXIST) { ret = sem_create(key, &semid); if(ret != 0) { printf("sem_create err\n"); return -1; } } int val= 1; ret = sem_set(semid, val);//設定訊號量計數值--預設設定第1個,下標位0 if(ret == -1) { printf("sem_set err\n"); return -1; } ret = sem_get(semid, &val);//獲取訊號量計數值 if(ret != 0) { printf("sem_get err\n"); return -1; } printf("val:%d\n",val); for(i= 0; i < proc_num;i++) { pid = fork(); if(0 == pid) { sem_p(semid);//p操作 printf("child : %d\tparent : %d\n",getpid(),getppid());//父程序如果退出以後,會將建立的子程序託孤給init程序--1號程序--父程序的PID就是1 for(j = 0;j < loop_num;j++) { Test(j); } sem_v(semid);//v操作 //一旦子程序完成任務立即結束子程序--避免子程序執行下一次迴圈的fork--避免子生孫 //程序結束的同時,Linux核心還會自動撤銷當前程序與共享記憶體的對映關係 exit(0); //如果程序不結束,則對映關係不會自動解除,除非顯示呼叫shmdt函式, //則ipcs命令看到的ntach選項就是所有程序的數量--表示多少個程序與該塊記憶體連線 //while(1); } } wait(NULL); IPC_DelShm(shmdl); return 0; }

訊號量模組

標頭檔案


#ifndef __MYIPC_SEM_H__
#define __MYIPC_SEM_H__

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>

#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>

#define SEM_NUM 1

#define SEMERR_BASE 100
#define SEMERR_PARAM (SEMERR_BASE+1)
#define SEMERR_EXIST (SEMERR_BASE+2)
#define SEMERR_ENOXIST (SEMERR_BASE+3)


typedef union semun {
   int              val;    /* Value for SETVAL */
   struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
   unsigned short  *array;  /* Array for GETALL, SETALL */
   struct seminfo  *__buf;  /* Buffer for IPC_INFO
                               (Linux-specific) */
}semun_t;

#if 0
typedef struct sembuf{
  unsigned short sem_num;  /* semaphore number */
  short          sem_op;   /* semaphore operation */
  short          sem_flg;  /* operation flags */
}sembuf_t;
#endif

typedef struct sembuf sembuf_t;

int sem_create(key_t key,int *semid);
int sem_open(key_t key,int *semid);
int sem_set(int semid,int val);
int sem_get(int semid,int* val);
int sem_p(int semid);
int sem_v(int semid);

#endif

實現檔案

#include "myipc_sem.h"

//封裝建立訊號量集合的程式碼
int sem_create(key_t key,int *semid)
{
  int sem_id = 0;
  int ret = 0;

  if(semid == NULL)
  {
    ret = SEMERR_PARAM;
    perror("argv err\n");
    return ret;
  }
  sem_id = semget(key,SEM_NUM,0666|IPC_CREAT|IPC_EXCL);
  if(sem_id == -1)
  {
    ret = SEMERR_EXIST;
    perror("semget");
    if(errno == EEXIST)
    {
      printf("Judge by self..exist\n");
    }
    return ret;
  }
  *semid = sem_id;

  return ret;
}

//封裝開啟已存在的訊號量集合
int sem_open(key_t key,int *semid)
{
  int sem_id = 0;
  int ret = 0;

  if(semid == NULL)
  {
    ret = SEMERR_PARAM;

    perror("argv err\n");
    return ret;
  }
  sem_id = semget(key,SEM_NUM,0666);
  if(sem_id == -1)
  {
    if(errno == ENOENT)
    {
      printf("Judge by self..exist\n");
      ret = SEMERR_ENOXIST;
      return ret;
    }
  }
  *semid = sem_id;

  return ret;
}

//設定訊號量集合裡面的訊號量的計數值
int sem_set(int semid,int val)
{
  int ret = 0;

  if(semid < 0)
  {
    return -1;
  }
  semun_t su;
  su.val = val;
  ret = semctl(semid,0,SETVAL,su);
  return ret;
}

//獲取訊號量集合裡面的訊號量的計數值
int sem_get(int semid,int* val)
{
  int ret = 0;
  if(semid < 0)
  {
    return -1;
  }
  semun_t su;
  ret = semctl(semid,0,GETVAL,su);//這裡需要特別注意
  if(ret == -1)//返回-1表示semctl失敗--直接返回
    return ret;
  else//非零表示獲取成功--但是返回值需要設定位0--上層應用收到0表示呼叫成功
    ret = 0;
  *val = su.val;//將獲取到的值甩出去到上層應用
  return ret;
}


//原子p操作
int sem_p(int semid)
{
  int ret = 0;

  sembuf_t buf = {0,-1,0};//一般預設是從第0個訊號量開始,第三個引數預設是0表示阻塞模式

  ret = semop(semid,&buf,1 );//只操作一個訊號量

  return ret;
}

//原子v操作
int sem_v(int semid)
{
  int ret = 0;

  sembuf_t buf = {0,+1,0};//一般預設是從第0個訊號量開始,第三個引數預設是0表示阻塞模式

  ret = semop(semid,&buf,1);//只操作一個訊號量

  return ret;
}

共享記憶體模組

標頭檔案


#ifndef __MYIPC_SHM_H__
#define __MYIPC_SHM_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define _OS_LINUX_

#if defined _OS_LINUX_
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <memory.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include "myipc_shm.h" 

#endif


#ifdef __cplusplus 
extern "C" {
#endif

int IPC_CreatShm(char *shmseedfile, int shmsize, int *shmhdl);

int IPC_MapShm(int shmhdl,void **mapaddr);

int IPC_UnMapShm(void *unmapaddr);

int IPC_DelShm(int shmhdl);


#ifdef __cplusplus
}
#endif
#endif


實現檔案


#include "myipc_shm.h"

int shmflag = 0;
int shmkey;

/***********************************************************************
  功能描述:    建立共享記憶體
  引數說明:    shmname  [in]  是共享記憶體名,系統中唯一標誌
                shmsize  [in]  是要建立的共享記憶體的大小;
                shmhdl   [out] 共享記憶體的控制代碼.
  返回值:      返回0函式執行成功;非0返回錯誤碼
************************************************************************/
int IPC_CreatShm(char *shmseedfile, int shmsize, int *shmhdl)
{
    if(shmflag == 0)            //判斷介面中共享記憶體key是否已經存在
    {
        shmkey = ftok(shmseedfile, 'c');
        if (shmkey == -1)
        {
            perror("ftok");
            return -1;
        }

        shmflag = 1;
    }

    //建立共享記憶體
    *shmhdl = shmget(shmkey,shmsize,IPC_CREAT|0666);
    if (*shmhdl == -1)          //建立失敗
        return -2;
    return 0;

}
/***********************************************************************
  功能描述:    關聯共享記憶體
  引數說明:    shmhdl   [in]  共享的控制代碼
                mapaddr [out] 共享記憶體首地址
  返回值:      返回0函式執行成功;非0返回錯誤碼
************************************************************************/
int
IPC_MapShm(int  shmhdl, void  **mapaddr)
{
    void *tempptr = NULL;

    //連線共享記憶體
    tempptr = (void *)shmat(shmhdl,0,SHM_RND);
    if (tempptr == (void*)-1)       //共享記憶體連線失敗
        return -1;
    *mapaddr = tempptr;         //匯出共享記憶體首指標

    return 0;
}
/***********************************************************************
  功能描述:    取消共享記憶體關聯
  引數說明:    unmapaddr   [in] 共享記憶體首地址
  返回值:      返回0函式執行成功;非0返回錯誤碼
************************************************************************/
int IPC_UnMapShm(void *unmapaddr)
{
    int  rv;
    //取消連線共享記憶體 
    rv = shmdt((char *)unmapaddr);
    if (rv == -1)           //取消連線失敗
        return -1;

    return 0;
}
/***********************************************************************
  功能描述:    刪除共享記憶體
  引數說明:    shmhdl   [in]  共享的控制代碼
  返回值:      返回0函式執行成功;非0返回錯誤碼
************************************************************************/
int IPC_DelShm(int shmhdl)
{
    int  rv;
    //刪除共享記憶體
    rv = shmctl(shmhdl,IPC_RMID,NULL);
    if(rv < 0)              //刪除共享記憶體失敗
        return -1;
    return 0;
}

Makefile檔案

CC=gcc
CFLAGS=-Wall -g
BIN=app 
.PHONY:clean all 

all:$(BIN)
$(BIN):mulfork.o myipc_sem.o myipc_shm.o
    $(CC) $(CFLAGS) $^ -o [email protected]
%.o:%.c 
    $(CC) $(CFLAGS) -c $^ -o [email protected]

clean:
    rm -f *.o $(BIN)

相關推薦

程序+共享記憶體+訊號綜合例項

測試框架 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sy

程序間通訊機制(管道、訊號共享記憶體/訊號/訊息佇列)、執行緒間通訊機制(互斥鎖、條件變數、posix匿名訊號

(1)系統中每個訊號量的資料結構(sem)struct sem {     int semval; /* 訊號量的當前值 */     unsigned short  semzcnt;  /* # waiting for zero */     unsigned short  semncnt;  /* # w

Python程序,同步互斥,訊號,鎖補充上一篇文章

from multiprocessing import Event,Process from time import sleep def wait_event1(): print("1想操作臨界區資源") e.wait() print("1開始操作臨界區資源",e.is_set()

python程序共享記憶體,我喜歡解除安裝思維導圖裡面,現在還沒有寫全,python得ctype,還沒有特別得熟悉

多程序與多執行緒頭大啊 1.C++ 將程序執行在指定的CPU上 1.1.https://blog.csdn.net/w2014qian/article/details/51941549 2.多程序 2.1.管道通訊 2.1.1.程序start啟動程序 join阻

程序共享記憶體續篇-大鎖

讀寫鎖,就是多人可以同時訪問,但是同時只有一個人可以修改的規則。 由於鎖本身的申請和釋放,對於效能有很大的消耗,那麼一般寫只發生在特殊情況,也就是很少發生。 讀鎖常在就是效能的優化方案,只有在申請寫鎖的時候,才會釋放讀鎖。 和之前有什麼不一樣呢,例如,連續的在不同地方的10

程序程序共享記憶體

這樣也可節約很多空間啊,找到了這片部落格寫的很好,怎麼能錯過記錄。感謝原作者。 HANDLE hmapfile = OpenFileMapppingA(FILE_MAP_READ, FALSE, "shijiaxing");    //開啟共享記憶體,可以用於程序通訊,

【Linux】程序間通訊-訊號詳解及程式設計例項

前面一篇文章執行緒同步之訊號量同步 講的是執行緒之間的訊號量,這篇講的更加具有通用性,能夠實現程序之間的同步。 訊號量概述 訊號量定義: 它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作。 P(訊號量變數sv):等待。如果sv大於0,減小sv。如果sv為0,掛起這

程序間通訊--訊號詳解及程式設計例項

訊號量概述 訊號量定義: 它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作。 P(訊號量變數sv):等待。如果sv大於0,減小sv。如果sv為0,掛起這個程序的執行。V(訊號量變數sv):傳送訊號。如果有程序被掛起等待sv,使其恢復執行。如果沒有進行被掛起等待sv

linux的程序通訊:訊號例項(C語言)

 這篇發的很糾結,這不是我原創的程式碼,是同學寫的,我只是想在這記錄下來,以後沒事可以看看,寫轉載嘛,又沒有轉載的來源,翻譯就更扯了,勉強寫個原創,其實不是我原創啦。 ( ̄▽ ̄)" 有興趣可以看下,這是關於linux中的訊號量的使用的一篇文章。我加了一些註釋。 題目是:寫一個程式,該程式建立兩個程序,分

程序間通訊-訊號詳解及程式設計例項

前面一篇文章執行緒同步之訊號量同步 講的是執行緒之間的訊號量,這篇講的更加具有通用性,能夠實現程序之間的同步。 訊號量概述 訊號量定義: 它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作。 P(訊號量變數sv):等待。如果sv大於0,減小sv。如果sv為0,掛

執行緒,訊號的簡單使用 GCD

基本概念 關於iOS開發中,多執行緒基本的概念和基本使用,我在這裡就不在重複說了。但是為了照顧到有的同學可能還不是對基本的概念不熟悉,可以參考一下這篇文章併發其實很簡單 說說訊號量,併發數 如果你有計算機基礎,那麼下面這段話應該很簡單就能理解 訊號量就是一個資源計數器,對訊號

linux 執行緒之訊號 sem_init

1. 什麼是訊號量 linux sem 訊號量是一種特殊的變數,訪問具有原子性, 用於解決程序或執行緒間共享資源引發的同步問題。 使用者態程序對 sem 訊號量可以有以下兩種操作: 等待訊號量 當訊號量值為 0 時,程式等待;當訊號量值大於 0 時,訊號量減 1,程式

PYTHON——執行緒:訊號(Semaphore)

  訊號量也是一把鎖,用來控制執行緒併發數的。   BoundedSemaphore或Semaphore管理一個內建的計數 器,每當呼叫acquire()時-1,呼叫release()時+1。       計數器不能小於0,當計數器為 0時,acquire()將阻塞執行緒至同

php程序間通訊--訊號

 訊號量是什麼? 訊號量 : 又稱為訊號燈、旗語 用來解決程序(執行緒同步的問題),類似於一把鎖,訪問前獲取鎖(獲取不到則等待),訪問後釋放鎖。   舉一個生活中的例子:以一個停車場的運作為例。簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許

作業系統-程序通訊(訊號、匿名管道、命名管道、Socket)

程序通訊(訊號量、匿名管道、命名管道、Socket) 具體的概念就沒必要說了,參考以下連結。 訊號量 匿名管道 命名管道 Socket Source Code: 1. 訊號量(生產者消費者問題) 1 #include <iostream>

python 程序共享類物件

理論上2和3版本都能用 from multiprocessing import Process, Value, Lock from multiprocessing.managers import BaseManager class Employee(object):

【swoole快速入門11】程序共享資料

由於PHP語言不支援多執行緒,因此Swoole使用多程序模式。在多程序模式下存在程序記憶體隔離,在工作程序內修改global全域性變數和超全域性變數時,在其他程序是無效的。 程序隔離 $fds = array(); $server->on('connect', fu

linux程序控制之訊號 semget,semctl,semop

轉載自 https://www.cnblogs.com/52php/p/5851570.html 這篇文章將講述別一種程序間通訊的機制——訊號量。注意請不要把它與之前所說的訊號混淆起來,訊號與訊號量是不同的兩種事物。有關訊號的更多內容,可以閱讀我的另一篇文章:L

執行緒之訊號Semaphore及原理

一、訊號量(Semaphore) 重入鎖ReentrantLock是獨佔模式,一次都只允許一個執行緒訪問一個資源,而訊號量是共享模式,也就是說可以指定多個執行緒,同時訪問某一個資源。 Semaphore的兩個構造方法: public Semaphore(int pe

Linux程式設計學習筆記----System V程序間通訊(訊號)

關於System V Unix System V,是Unix作業系統眾多版本中的一支。它最初由AT&T開發,在1983年第一次釋出,因此也被稱為AT&T System V。一共發行了4個System V的主要版本:版本1、2、3和4。System V Rel