簡體   English   中英

C-共享內存和信號量

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM