[英]C - Shared memory and semaphores
我想創建一個具有共享內存和信號量的C程序。 應該有兩個子進程。 兩個孩子都有不同的int數。 然后有一個目標號應寫入共享內存中。 現在,兩個孩子都應該從目標編號中減去其編號,直到目標編號小於或等於0。我不希望出現比賽條件。 這就是為什么我嘗試使用信號量的原因。 但這對我不起作用。 這是我的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/sem.h>
#define SEG_SIZE sizeof(int)
#define NUM_OF_CHILDS 2
int main(int argc, char *argv[]){
int i, shm_id, sem_id, *shar_mem;
int pid[NUM_OF_CHILDS];
long waittime = 100;
unsigned short marker[1];
/* Define the numbers and the goal number */
int numbers[2] = {28, 23};
int goal = (numbers[0] + numbers[1]) * 4;
/* Create semaphor */
if((sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT|0644)) == -1){
perror("semget()");
exit(EXIT_FAILURE);
}
marker[0] = 1;
/* All sem's to 1 */
semctl(sem_id, 1, SETALL, marker);
/* Create shared memory */
if((shm_id = shmget(IPC_PRIVATE, SEG_SIZE, IPC_CREAT|0600)) == -1){
perror("shmget()");
exit(EXIT_FAILURE);
}
if((shar_mem = (int *)shmat(shm_id, 0, 0)) == (int *) -1){
perror("shmat()");
exit(EXIT_FAILURE);
}
*shar_mem = goal;
/* Create child processes */
for(i = 0; i < NUM_OF_CHILDS; i++){
pid[i] = fork();
if(pid[i] < 0){
printf("Error!\n");
exit(1);
}
if(pid[i] == 0){
int count = 0;
/* Child processes */
/* Structs for semaphor */
struct sembuf enter, leave;
enter.sem_num = leave.sem_num = 0;
enter.sem_flg = leave.sem_flg = SEM_UNDO;
enter.sem_op = -1; /* DOWN-Operation */
leave.sem_op = 1; /* UP-Operation */
/* Join critical area */
semop(sem_id, &enter, 1);
while(*shar_mem > 0){
usleep(waittime);
*shar_mem -= numbers[i];
count++;
}
printf("%i\n", count);
/* Leave critical area */
semop(sem_id, &leave, 1);
exit(0);
}
}
/* Wait for childs. */
for(i = 0; i < NUM_OF_CHILDS; i++){
waitpid(pid[i], NULL, 0);
}
/* Is goal equal 0 or lower? */
int returnv;
if(*shar_mem == 0){
/* No race conditions */
returnv = 0;
}
else {
/* Race conditions */
returnv = 1;
}
/* Close shared memory and semaphores */
shmdt(shar_mem);
shmctl(shm_id, IPC_RMID, 0);
semctl(sem_id, 0, IPC_RMID);
return returnv;
}
最后,如果共享內存值為0,則不應存在爭用條件。 如果它小於0,則說明存在競爭條件。 而且我總是低於0。最重要的是,我計算每個孩子減去他的數字的次數。 結果:第一個孩子8次,第二個孩子0次。 有人可以幫我嗎?
使您的while循環適應這樣的情況,以便在減去一次后離開關鍵部分:
for ( ; ; ) {
usleep(waittime);
semop(sem_id, &enter, 1);
if (*shar_mem <= 0) {
semop(sem_id, &leave, 1);
break;
}
*shar_mem -= numbers[i];
semop(sem_id, &leave, 1);
count++;
}
但是,正如我的評論中所述,不能保證兩個孩子都交替減去他們的數字,即結果可能小於零
在您評論的評論中:
我試圖將semop部分放入循環中。 現在第一個孩子有8個計數,第二個孩子有1個計數。 [...]我必須使用信號量。
顯然,僅將關鍵部分邊界移入循環內部是不夠的。 這是因為無法保證當一個進程通過增加信號量而離開關鍵部分時,另一進程將立即進入關鍵部分。 相反,第一個過程可能會循環,然后在第二個部分進入關鍵部分之前重新輸入它。 實際上,該結果很可能是因為循環很緊,而且我們知道退出關鍵部分的進程當前已在某些CPU上調度。
可以通過在關鍵部分之外的環路中引入延遲來解決該問題,但這有點麻煩。 一方面,它不必要地減慢了程序速度。 另一方面,盡管足夠長的延遲可以使問題極不可能出現,但是沒有多少延遲可以保證問題不會顯現。 您始終受制於系統調度程序。 但是,由於您已經有了延遲,因此您也可以通過將其置於關鍵部分之外,使所需的行為很可能得到體現。
有幾種處理此問題的方法,可以提供各種所需的語義而不會造成人為的延遲。 它們全部涉及至少一個以上的信號量。 以下是兩種可能性:
為每個進程創建一個單獨的信號燈。 選擇一個初始化為1的變量,將其余初始化為0的變量。在循環的頂部,每個進程都會減少自己的信號量,在底部,它會增加下一個進程的信號量。 然后,這些過程以循環方式運行。
除了用於保護關鍵部分的信號燈之外,還可以使用兩個其他信號燈在循環的頂部創建“循環屏障”。 循環屏障是一種可重用的構造,它使一些固定數量的進程/線程在它們中的任何一個可以繼續進行之前都到達給定的點。 這不會使進程嚴格交替,但可以防止任何進程比其他進程提前一個以上的循環迭代。 它的優點是,無論要協調多少個進程,它都只需要三個信號燈。
前者更容易概念化和編寫,即使它為流程訂購提供了更有力的保證。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.