在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Linux/ 信號(hào)量
命名管道
消息隊(duì)列
進(jìn)程創(chuàng)建與終止
信號(hào)量
進(jìn)程組,會(huì)話(huà)和作業(yè)控制
共享內(nèi)存
進(jìn)程間通信簡(jiǎn)介
子進(jìn)程監(jiān)視
其他進(jìn)程
覆蓋進(jìn)程映像
進(jìn)程信息
進(jìn)程映像
內(nèi)存映射
相關(guān)系統(tǒng)調(diào)用(System V)
進(jìn)程資源
System V & Posix
信號(hào)
進(jìn)程間通信教程
管道

信號(hào)量

首先想到的問(wèn)題是,為什么我們需要信號(hào)量? 一個(gè)簡(jiǎn)單的答案,以保護(hù)多個(gè)進(jìn)程共享的關(guān)鍵/共同區(qū)域。

假設(shè)多個(gè)進(jìn)程正在使用相同的代碼區(qū)域,如果所有人都想并行訪問(wèn),那么結(jié)果是重疊的。 例如,多個(gè)用戶(hù)僅使用一臺(tái)打印機(jī)(通用/關(guān)鍵部分),例如3個(gè)用戶(hù),同時(shí)給予3個(gè)作業(yè),如果所有作業(yè)并行啟動(dòng),則一個(gè)用戶(hù)輸出與另一個(gè)用戶(hù)輸出重疊。 因此,我們需要使用信號(hào)量來(lái)保護(hù)這個(gè)信號(hào),即當(dāng)一個(gè)進(jìn)程正在運(yùn)行時(shí)鎖定關(guān)鍵部分,并在完成時(shí)解鎖。 這將為每個(gè)用戶(hù)/進(jìn)程重復(fù),以便一個(gè)作業(yè)不與另一個(gè)作業(yè)重疊。

基本上信號(hào)量分為兩類(lèi) -

  • 二進(jìn)制信號(hào) - 只有兩個(gè)狀態(tài)01,即鎖定/解鎖或可用/不可用,互斥實(shí)現(xiàn)。
  • 計(jì)算信號(hào)量 - 允許任意資源計(jì)數(shù)的信號(hào)量稱(chēng)為計(jì)數(shù)信號(hào)量。

假設(shè)有5臺(tái)打印機(jī)(要了解1臺(tái)打印機(jī)只接受1一項(xiàng)工作),我們有3個(gè)打印作業(yè)。 現(xiàn)在有三個(gè)打印機(jī)(每個(gè)打印機(jī)1個(gè))提供3個(gè)工作。 這項(xiàng)工作還在進(jìn)行中,共有4項(xiàng)工作。 現(xiàn)在,在可用的兩臺(tái)打印機(jī)中,已經(jīng)安排了兩個(gè)作業(yè),剩下兩個(gè)作業(yè),只有在其中一個(gè)資源/打印機(jī)可用時(shí)才能完成。 根據(jù)資源可用性的這種調(diào)度可以被看作計(jì)數(shù)信號(hào)量。

要使用信號(hào)量執(zhí)行同步,請(qǐng)執(zhí)行以下步驟 -

第1步 - 創(chuàng)建一個(gè)信號(hào)量或連接到一個(gè)已經(jīng)存在的信號(hào)量(semget())
第2步 - 對(duì)信號(hào)量執(zhí)行操作,即分配或釋放或等待資源(semop())
第3步 - 在消息隊(duì)列(semctl())上執(zhí)行控制操作

現(xiàn)在,讓我們查看一下系統(tǒng)調(diào)用。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg)

這個(gè)系統(tǒng)調(diào)用創(chuàng)建或分配一個(gè)System V信號(hào)集。 需要傳遞以下參數(shù) -

  • 第一個(gè)參數(shù)key用于識(shí)別消息隊(duì)列。key可以是任意值,也可以是來(lái)自庫(kù)函數(shù)ftok()的值。
  • 第二個(gè)參數(shù)nsems指定了信號(hào)的數(shù)量。 如果二進(jìn)制那么它是1,意味著需要1個(gè)信號(hào)集,否則按照所需的信號(hào)量集計(jì)數(shù)。
  • 第三個(gè)參數(shù)semflg指定所需的信號(hào)量標(biāo)志,如IPC_CREAT(如果不存在則創(chuàng)建信號(hào)量)或IPC_EXCL(與IPC_CREAT一起用于創(chuàng)建信號(hào)量,如果信號(hào)量已經(jīng)存在,則調(diào)用失敗)。 還需要傳遞權(quán)限。

    注 - 有關(guān)權(quán)限的詳細(xì)信息,請(qǐng)參閱前面幾節(jié)。

這個(gè)調(diào)用會(huì)在成功時(shí)返回有效的信號(hào)量標(biāo)識(shí)符(用于進(jìn)一步調(diào)用信號(hào)量),在失敗的情況下返回-1。 要知道失敗的原因,請(qǐng)檢查errno變量或perror()函數(shù)。

關(guān)于這個(gè)調(diào)用的各種錯(cuò)誤是EACCESS(權(quán)限被拒絕),EEXIST(隊(duì)列已經(jīng)存在不能創(chuàng)建),ENOENT(隊(duì)列不存在),ENOMEM(沒(méi)有足夠的內(nèi)存來(lái)創(chuàng)建隊(duì)列),ENOSPC(最大限制 超過(guò))等

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *semops, size_t nsemops)

這個(gè)系統(tǒng)調(diào)用在System V信號(hào)集上執(zhí)行操作,即分配資源,等待資源或釋放資源。 以下參數(shù)需要傳遞 -

  • 第一個(gè)參數(shù)semid指示由semget()創(chuàng)建的信號(hào)集標(biāo)識(shí)符。
  • 第二個(gè)參數(shù)semops是指向要在信號(hào)集上執(zhí)行的操作數(shù)組的指針。 結(jié)構(gòu)如下 -
    struct sembuf {
     unsigned short sem_num; /* Semaphore set num */
     short sem_op; /* Semaphore operation */
     short sem_flg; /* Operation flags, IPC_NOWAIT, SEM_UNDO */
    };
    
    上述結(jié)構(gòu)中的元素sem_op指示需要執(zhí)行的操作 -
    • 如果sem_op-ve,則分配或獲取資源。 阻塞調(diào)用進(jìn)程,直到其他進(jìn)程釋放了足夠的資源,以便此進(jìn)程可以分配。
    • 如果sem_op0,則調(diào)用進(jìn)程等待或休眠,直到信號(hào)量值達(dá)到0。
    • 如果sem_op+ve,則釋放資源。
  • 第三個(gè)參數(shù)nsemops是該數(shù)組中的操作數(shù)。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, …)

此系統(tǒng)調(diào)用執(zhí)行System V信號(hào)量的控制操作。 以下參數(shù)需要傳遞 -

  • 第一個(gè)參數(shù)semid是信號(hào)量的標(biāo)識(shí)符。 這個(gè)id是信號(hào)量標(biāo)識(shí)符,它是semget()系統(tǒng)調(diào)用的返回值。
  • 第二個(gè)參數(shù)semnum是信號(hào)量的數(shù)量。 信號(hào)量從0開(kāi)始編號(hào)。
  • 第三個(gè)參數(shù)cmd是在信號(hào)量上執(zhí)行所需控制操作的命令。
  • 第四個(gè)參數(shù)是union semun,取決于cmd。 少數(shù)情況下,第四個(gè)參數(shù)是不適用的。

讓我們來(lái)看看union semun -

union semun {
   int val; /* val for SETVAL */
   struct semid_ds *buf; /* Buffer for IPC_STAT and IPC_SET */
   unsigned short *array; /* Buffer for GETALL and SETALL */
   struct seminfo *__buf; /* Buffer for IPC_INFO and SEM_INFO*/
};

sys/sem.h中定義的semid_ds數(shù)據(jù)結(jié)構(gòu)如下所示 -

struct semid_ds {
   struct ipc_perm sem_perm; /* Permissions */
   time_t sem_otime; /* Last semop time */
   time_t sem_ctime; /* Last change time */
   unsigned long sem_nsems; /* Number of semaphores in the set */
};

注 - 請(qǐng)參閱手冊(cè)頁(yè)以獲取其他數(shù)據(jù)結(jié)構(gòu)。

union semun arg的有效值是 -

  • IPC_STAT - 將struct semid_ds的每個(gè)成員的當(dāng)前值的信息復(fù)制到arg.buf指向的傳遞結(jié)構(gòu)。 該命令需要信號(hào)量的讀取權(quán)限。
  • IPC_SET - 設(shè)置結(jié)構(gòu)semid_ds指向的用戶(hù)ID,所有者的組ID,權(quán)限等。
  • IPC_RMID - 刪除信號(hào)集。
  • IPC_INFO - 返回有關(guān)arg.__ buf指向的semid_ds結(jié)構(gòu)中的信號(hào)限制和參數(shù)的信息。
  • SEM_INFO - 返回一個(gè)包含有關(guān)信號(hào)量消耗的系統(tǒng)資源信息的seminfo結(jié)構(gòu)。

這個(gè)調(diào)用將根據(jù)傳遞的命令返回值(非負(fù)值)。 一旦成功,IPC_INFO和SEM_INFO或SEM_STAT返回根據(jù)Semaphore的最高使用條目的索引或標(biāo)識(shí)符,或GETPID的semncnt值或GETPID的sempid值或GETVAL 0的semval值, 1在失敗的情況下。 要知道失敗的原因,請(qǐng)檢查errno變量或perror()函數(shù)。

在看代碼之前,讓我們了解它的實(shí)現(xiàn) -

  • 創(chuàng)建兩個(gè)進(jìn)程 - 子進(jìn)程和父進(jìn)程。
  • 創(chuàng)建共享內(nèi)存主要需要存儲(chǔ)計(jì)數(shù)器和其他標(biāo)志,以指示讀/寫(xiě)過(guò)程結(jié)束到共享內(nèi)存中。
  • 計(jì)數(shù)器由父進(jìn)程和子進(jìn)程的計(jì)數(shù)遞增。 計(jì)數(shù)可以作為命令行參數(shù)傳遞,也可以作為默認(rèn)值(如果不作為命令行參數(shù)傳遞,或者值小于10000)。 被調(diào)用一定的睡眠時(shí)間,以確保父母和孩子同時(shí)訪問(wèn)共享內(nèi)存,即并行訪問(wèn)。
  • 由于父進(jìn)程和子進(jìn)程的計(jì)數(shù)器都是以1為單位遞增,所以最終的數(shù)值應(yīng)該是計(jì)數(shù)器的兩倍。 因?yàn)楦?,子進(jìn)程同時(shí)執(zhí)行這些操作,所以計(jì)數(shù)器不會(huì)按需要遞增。 因此,我們需要確保一個(gè)進(jìn)程完成之后的其他過(guò)程的完整性。
  • 以上所有的實(shí)現(xiàn)都在shm_write_cntr.c文件中執(zhí)行
  • 檢查計(jì)數(shù)器值是否在文件shm_read_cntr.c中實(shí)現(xiàn)
  • 為了確保完成,信號(hào)量程序在文件shm_write_cntr_with_sem.c中實(shí)現(xiàn)。 在完成整個(gè)過(guò)程(從其他程序完成讀取之后)中刪除信號(hào)量
  • 由于有單獨(dú)的文件來(lái)讀取共享內(nèi)存中的計(jì)數(shù)器的值,并且沒(méi)有任何影響,讀取程序保持不變(shm_read_cntr.c)
  • 在一個(gè)終端上執(zhí)行寫(xiě)入程序并從另一個(gè)終端上讀取程序總是比較好的。 因?yàn)槌绦蛑挥性趯?xiě)入和讀取過(guò)程完成之后才能完成執(zhí)行,那么在完全執(zhí)行寫(xiě)入程序之后運(yùn)行程序就可以了。 寫(xiě)程序?qū)⒁恢钡鹊阶x程序運(yùn)行,并且只有在完成后才能完成。

沒(méi)有信號(hào)量的程序 -

/* Filename: shm_write_cntr.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>

#define SHM_KEY 0x12345
struct shmseg {
   int cntr;
   int write_complete;
   int read_complete;
};
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count);

int main(int argc, char *argv[]) {
   int shmid;
   struct shmseg *shmp;
   char *bufptr;
   int total_count;
   int sleep_time;
   pid_t pid;
   if (argc != 2)
   total_count = 10000;
   else {
      total_count = atoi(argv[1]);
      if (total_count < 10000)
      total_count = 10000;
   }
   printf("Total Count is %d\n", total_count);
   shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);

   if (shmid == -1) {
      perror("Shared memory");
      return 1;
   }

   // Attach to the segment to get a pointer to it.
   shmp = shmat(shmid, NULL, 0);
   if (shmp == (void *) -1) {
      perror("Shared memory attach");
      return 1;
   }
   shmp->cntr = 0;
   pid = fork();

   /* Parent Process - Writing Once */
   if (pid > 0) {
      shared_memory_cntr_increment(pid, shmp, total_count);
   } else if (pid == 0) {
      shared_memory_cntr_increment(pid, shmp, total_count);
      return 0;
   } else {
      perror("Fork Failure\n");
      return 1;
   }
   while (shmp->read_complete != 1)
   sleep(1);

   if (shmdt(shmp) == -1) {
      perror("shmdt");
      return 1;
   }

   if (shmctl(shmid, IPC_RMID, 0) == -1) {
      perror("shmctl");
      return 1;
   }
   printf("Writing Process: Complete\n");
   return 0;
}

/* Increment the counter of shared memory by total_count in steps of 1 */
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count) {
   int cntr;
   int numtimes;
   int sleep_time;
   cntr = shmp->cntr;
   shmp->write_complete = 0;
   if (pid == 0)
   printf("SHM_WRITE: CHILD: Now writing\n");
   else if (pid > 0)
   printf("SHM_WRITE: PARENT: Now writing\n");
   //printf("SHM_CNTR is %d\n", shmp->cntr);

   /* Increment the counter in shared memory by total_count in steps of 1 */
   for (numtimes = 0; numtimes < total_count; numtimes++) {
      cntr += 1;
      shmp->cntr = cntr;

      /* Sleeping for a second for every thousand */
      sleep_time = cntr % 1000;
      if (sleep_time == 0)
      sleep(1);
   }

   shmp->write_complete = 1;
   if (pid == 0)
   printf("SHM_WRITE: CHILD: Writing Done\n");
   else if (pid > 0)
   printf("SHM_WRITE: PARENT: Writing Done\n");
   return;
}

執(zhí)行上面程序代碼,得到以下結(jié)果 -

Total Count is 10000
SHM_WRITE: PARENT: Now writing
SHM_WRITE: CHILD: Now writing
SHM_WRITE: PARENT: Writing Done
SHM_WRITE: CHILD: Writing Done
Writing Process: Complete

現(xiàn)在讓我們來(lái)看看共享內(nèi)存讀取程序的實(shí)現(xiàn) -

/* Filename: shm_read_cntr.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>

#define SHM_KEY 0x12345
struct shmseg {
   int cntr;
   int write_complete;
   int read_complete;
};

int main(int argc, char *argv[]) {
   int shmid, numtimes;
   struct shmseg *shmp;
   int total_count;
   int cntr;
   int sleep_time;
   if (argc != 2)
   total_count = 10000;

   else {
      total_count = atoi(argv[1]);
      if (total_count < 10000)
      total_count = 10000;
   }
   shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);

   if (shmid == -1) {
      perror("Shared memory");
      return 1;
   }
   // Attach to the segment to get a pointer to it.
   shmp = shmat(shmid, NULL, 0);

   if (shmp == (void *) -1) {
      perror("Shared memory attach");
      return 1;
   }

   /* Read the shared memory cntr and print it on standard output */
   while (shmp->write_complete != 1) {
      if (shmp->cntr == -1) {
         perror("read");
         return 1;
      }
      sleep(3);
   }
   printf("Reading Process: Shared Memory: Counter is %d\n", shmp->cntr);
   printf("Reading Process: Reading Done, Detaching Shared Memory\n");
   shmp->read_complete = 1;

   if (shmdt(shmp) == -1) {
      perror("shmdt");
      return 1;
   }
   printf("Reading Process: Complete\n");
   return 0;
}

執(zhí)行上面程序代碼,得到以下結(jié)果 -

Reading Process: Shared Memory: Counter is 11000
Reading Process: Reading Done, Detaching Shared Memory
Reading Process: Complete

如果觀察到上面的輸出,計(jì)數(shù)器應(yīng)該是20000,但是,因?yàn)樵谝粋€(gè)進(jìn)程任務(wù)完成之前其他進(jìn)程也是并行處理的,所以計(jì)數(shù)器值不是預(yù)期的。 每個(gè)系統(tǒng)的輸出會(huì)有所不同,而且每次執(zhí)行都會(huì)有所不同。 為了確保兩個(gè)進(jìn)程在完成一個(gè)任務(wù)后執(zhí)行任務(wù),應(yīng)該使用同步機(jī)制來(lái)實(shí)現(xiàn)。

現(xiàn)在,讓我們使用信號(hào)機(jī)制,看看下面相同的應(yīng)用程序。

- 讀取程序的實(shí)現(xiàn)保持不變。

/* Filename: shm_write_cntr_with_sem.c */
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>

#define SHM_KEY 0x12345
#define SEM_KEY 0x54321
#define MAX_TRIES 20

struct shmseg {
   int cntr;
   int write_complete;
   int read_complete;
};
void shared_memory_cntr_increment(int, struct shmseg*, int);
void remove_semaphore();

int main(int argc, char *argv[]) {
   int shmid;
   struct shmseg *shmp;
   char *bufptr;
   int total_count;
   int sleep_time;
   pid_t pid;
   if (argc != 2)
   total_count = 10000;
   else {
      total_count = atoi(argv[1]);
      if (total_count < 10000)
      total_count = 10000;
   }
   printf("Total Count is %d\n", total_count);
   shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);

   if (shmid == -1) {
      perror("Shared memory");
      return 1;
   }
   // Attach to the segment to get a pointer to it.
   shmp = shmat(shmid, NULL, 0);

   if (shmp == (void *) -1) {
      perror("Shared memory attach: ");
      return 1;
   }
   shmp->cntr = 0;
   pid = fork();

   /* Parent Process - Writing Once */
   if (pid > 0) {
      shared_memory_cntr_increment(pid, shmp, total_count);
   } else if (pid == 0) {
      shared_memory_cntr_increment(pid, shmp, total_count);
      return 0;
   } else {
      perror("Fork Failure\n");
      return 1;
   }
   while (shmp->read_complete != 1)
   sleep(1);

   if (shmdt(shmp) == -1) {
      perror("shmdt");
      return 1;
   }

   if (shmctl(shmid, IPC_RMID, 0) == -1) {
      perror("shmctl");
      return 1;
   }
   printf("Writing Process: Complete\n");
   remove_semaphore();
   return 0;
}

/* Increment the counter of shared memory by total_count in steps of 1 */
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count) {
   int cntr;
   int numtimes;
   int sleep_time;
   int semid;
   struct sembuf sem_buf;
   struct semid_ds buf;
   int tries;
   int retval;
   semid = semget(SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0666);
   //printf("errno is %d and semid is %d\n", errno, semid);

   /* Got the semaphore */
   if (semid >= 0) {
      printf("First Process\n");
      sem_buf.sem_op = 1;
      sem_buf.sem_flg = 0;
      sem_buf.sem_num = 0;
      retval = semop(semid, &sem_buf, 1);
      if (retval == -1) {
         perror("Semaphore Operation: ");
         return;
      }
   } else if (errno == EEXIST) { // Already other process got it
      int ready = 0;
      printf("Second Process\n");
      semid = semget(SEM_KEY, 1, 0);
      if (semid < 0) {
         perror("Semaphore GET: ");
         return;
      }

      /* Waiting for the resource */
      sem_buf.sem_num = 0;
      sem_buf.sem_op = 0;
      sem_buf.sem_flg = SEM_UNDO;
      retval = semop(semid, &sem_buf, 1);
      if (retval == -1) {
         perror("Semaphore Locked: ");
         return;
      }
   }
   sem_buf.sem_num = 0;
   sem_buf.sem_op = -1; /* Allocating the resources */
   sem_buf.sem_flg = SEM_UNDO;
   retval = semop(semid, &sem_buf, 1);

   if (retval == -1) {
      perror("Semaphore Locked: ");
      return;
   }
   cntr = shmp->cntr;
   shmp->write_complete = 0;
   if (pid == 0)
   printf("SHM_WRITE: CHILD: Now writing\n");
   else if (pid > 0)
   printf("SHM_WRITE: PARENT: Now writing\n");
   //printf("SHM_CNTR is %d\n", shmp->cntr);

   /* Increment the counter in shared memory by total_count in steps of 1 */
   for (numtimes = 0; numtimes < total_count; numtimes++) {
      cntr += 1;
      shmp->cntr = cntr;
      /* Sleeping for a second for every thousand */
      sleep_time = cntr % 1000;
      if (sleep_time == 0)
      sleep(1);
   }
   shmp->write_complete = 1;
   sem_buf.sem_op = 1; /* Releasing the resource */
   retval = semop(semid, &sem_buf, 1);

   if (retval == -1) {
      perror("Semaphore Locked\n");
      return;
   }

   if (pid == 0)
      printf("SHM_WRITE: CHILD: Writing Done\n");
      else if (pid > 0)
      printf("SHM_WRITE: PARENT: Writing Done\n");
      return;
}

void remove_semaphore() {
   int semid;
   int retval;
   semid = semget(SEM_KEY, 1, 0);
      if (semid < 0) {
         perror("Remove Semaphore: Semaphore GET: ");
         return;
      }
   retval = semctl(semid, 0, IPC_RMID);
   if (retval == -1) {
      perror("Remove Semaphore: Semaphore CTL: ");
      return;
   }
   return;
}

執(zhí)行上面示例代碼,得到以下結(jié)果 -

Total Count is 10000
First Process
SHM_WRITE: PARENT: Now writing
Second Process
SHM_WRITE: PARENT: Writing Done
SHM_WRITE: CHILD: Now writing
SHM_WRITE: CHILD: Writing Done
Writing Process: Complete

現(xiàn)在,我們將通過(guò)讀取進(jìn)程來(lái)檢查計(jì)數(shù)器值。執(zhí)行結(jié)果如下 -

Reading Process: Shared Memory: Counter is 20000
Reading Process: Reading Done, Detaching Shared Memory
Reading Process: Complete

上一篇:進(jìn)程資源