簡體   English   中英

使用信號量共享內存同步

[英]Shared memory sync using semaphore

我有兩個代碼: PRODUCER(PR)CONSUMER(CO) 有一個內存塊(Mat)(准確地說是3D矩陣),需要在兩個程序之間共享。 我目前正在使用基於共享內存的IPC函數在兩個代碼之間共享內存空間。

約束:

  1. PRMat的所有者,並執行迭代來更改矩陣的值。 COMat的用戶,僅讀取值並用於進一步的計算
  2. PR應該先寫入數據,然后等待CO讀取並使用Matrix的值,然后向PR發出信號以繼續進行進一步迭代,並且它應該像這樣繼續。

我目前正在使用的是-

生產者

#include <unistd.h>
#include  <stdio.h>
#include  <stdlib.h>
#include  <sys/types.h>
#include  <sys/ipc.h>
#include  <sys/shm.h>

#define  NOT_READY  -1
#define  FILLED     0
#define  TAKEN      1

#define  nx (400)
#define  ny (400)
#define  nz (400)

struct Memory {
     int      status;
     double   u_x[nx+1][ny+2][nz+2];
}

int 
main(int  argc, char *argv[])
{
     key_t          ShmKEY;
     int            ShmID;
     struct Memory  *ShmPTR;
     int            i, j, k;
     int            niter = 5;

     int            sumX[niter],sumY[niter],sumZ[niter];

     ShmKEY = ftok(".", 'x'); // getting the unique identifier key from directory location
     ShmID = shmget(ShmKEY, sizeof(struct Memory), IPC_CREAT | 0666);
     if (ShmID < 0) {
          printf("*** shmget error (server) ***\n");
          exit(1);
     }

     ShmPTR = (struct Memory *) shmat(ShmID, NULL, 0);
     if ((int) ShmPTR == -1) {
          printf("*** shmat error (server) ***\n");
          exit(1);
     }
     printf("Server attached the memory to its virtual space...\n");

     ShmPTR->status  = NOT_READY; // setting the status to be not ready before filling it

     for (int m = 0; m < niter; m++){
        for (i=0; i<=nx; i++) for (j=0; j<=ny+1; j++) for (k=0; k<=nz+1; k++) 
           ShmPTR->u_x[i][j][k] = m; // filling the array with iteration number (just for depiction purpose)
        ShmPTR->status = FILLED; // change the status to Filled
        //printf("Please start the client in another window...\n");
        while (ShmPTR->status != TAKEN)
             sleep(1);
     }

     printf("Server has detected the completion of its child...\n");
     shmdt((void *) ShmPTR);
     printf("Server has detached its shared memory...\n");
     shmctl(ShmID, IPC_RMID, NULL);
     printf("Server has removed its shared memory...\n");
     printf("Server exits...\n");
     exit(0);
}

消費者

#include  <stdio.h>
#include  <stdlib.h>
#include  <sys/types.h>
#include  <sys/ipc.h>
#include  <sys/shm.h>

#define  NOT_READY  -1
#define  FILLED     0
#define  TAKEN      1

#define  nx (400)
#define  ny (400)
#define  nz (400)

struct Memory {
    int      status;
    double   u_x[nx+1][ny+2][nz+2];
}

int
main(void)
{
    key_t          ShmKEY;
    int            ShmID;
    struct Memory  *ShmPTR;
    int            i, j, k;

    int            niter = 5;
    int            sumX[niter];

    ShmKEY = ftok(".", 'x');
    ShmID = shmget(ShmKEY, sizeof(struct Memory), 0666);
    if (ShmID < 0) {
          printf("*** shmget error (client) ***\n");
        exit(1);
    }
    printf("Client has received a shared memory...\n");

    ShmPTR = (struct Memory *) shmat(ShmID, NULL, 0);
    if ((int) ShmPTR == -1) {
        printf("*** shmat error (client) ***\n");
        exit(1);
    }
    printf("Client has attached the shared memory to it's virtual memory space...\n");

    for (int m =0; m<niter; m++){
        sumX[m] = 0;
        while (ShmPTR->status != FILLED)
            ;
        printf("Client found the data is ready, performing sanity check...\n");
        // read the integers and check for the sum

        for (i=0; i<=nx; i++) for (j=0; j<=ny+1; j++) for (k=0; k<=nz+1; k++) 
            sumX[m] +=  ShmPTR->u_x[i][j][k];
        printf("Cycle %d : sumX-> %d\n", m,sumX[m);

        ShmPTR->status = TAKEN;
        printf("Client has informed server data have been taken...\n");
    }
    shmdt((void *) ShmPTR);
    printf("Client has detached its shared memory...\n");
    printf("Client exits...\n");
    exit(0);
}

我現在正在做的是使用一種稱為status的結構成員來防止競爭。 從我到目前為止所讀的內容來看, 信號量在IPC中允許類似的事情。

問題:如何在這種情況下使用信號量,以便需要共享的存儲空間僅是數組,而不是將其包裝在帶有自定義標志的結構中?

Edit1:或者mutex量是否比此應用程序的信號量更好。

Edit2:在適用於此代碼的@Stargateur答案之后,但是在生產代碼中,其中nxnynz是變量,如何為由可變長度多維數組成員組成的結構定義共享內存 (當然它將一直存在,直到調用shmdtshmctl

我將建議您使用兩個信號量來實現您的功能,一個信號量用於解鎖produser,一個信號源用於解鎖consumer。

如何在這種情況下使用信號量,以便需要共享的存儲空間僅是數組,而不是將其包裝在帶有自定義標志的結構中?

是的,但是為什么要分離數據以及與數據關聯的信號量呢?

我將執行以下操作:

struct Memory {
     sem_t    prod;
     sem_t    cons;
     double   u_x[nx+1][ny+2][nz+2];
};

// produser
sem_init(&ShmPTR->cons, !0, 0);
sem_init(&ShmPTR->prod, !0, 1);

 for (int m = 0; m < niter; m++) {
     sem_wait(&ShmPTR->prod);
     // ...
     sem_post(&ShmPTR->cons);
 }

// consumer
for (int m =0; m<niter; m++) {
     sem_wait(&ShmPTR->cons);
     // ...
     sem_post(&ShmPTR->prod);
}

或者,互斥量是否比此應用程序的信號量更好。

互斥體不能在進程之間共享。

順便說一下,您使用int迭代數組,應該使用size_t

如果計划將PRCO保留為單獨的流程,則可以嘗試將其中一個流程與另一個流程進行分叉以使其同步。 在這種情況下,我的建議是從PR流程中派遣CO 這是我的想法:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>


int main(int argc, char* argv[])
{
    const char *name="SHARED";
    const int SIZE = 4096;


    pid_t pidA;
    pidA = fork();

    if (pidA < 0)
    {
        printf("forkA Failed" );
        return 1;
    }
    else if (pidA == 0) // Child process A
    {


        // Read from the shared memory object.


        exit(0);
    }
    else // Parent process
    {

        int shm_fd;
        /* pointer to shared memory obect */
        void* ptr;
        /* create the shared memory object */
        shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
        /* configure the size of the shared memory object */
        ftruncate(shm_fd, SIZE);
        /* memory map the shared memory object */
        ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);



        /* write to the shared memory object */



        // Wait for child to read matrix
        wait(NULL);


        printf("Program finished------\n");
    }
}

但是我們都知道線程更輕量 ,因此更可取 您可以將信號量與兩個線程一起使用,如下所示:

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

sem_t can_read,can_write; // declare two global semaphore

void* threadPR(void* arg)
{
  while(true)
  {
    //wait
    sem_wait(&can_write);


    //Write to matrix


    //signal
    sem_post(&can_read);
  }
}

void* threadCO(void* arg)
{
  while(true)
  {
    //wait
    sem_wait(&can_read);


    //Read the matrix


    //signal
    sem_post(&can_write);
  }
}


int main()
{
    // initialize the semaphore
    sem_init(&mutex, 0, 1);
    // declare two threads
    pthread_t t1,t2;
    pthread_create(&t1,NULL,threadPR,NULL); // Run the PR thread

    // do whatever needed before running CO

    pthread_create(&t2,NULL,threadCO,NULL); // Run the CO thread

    // wait for threads to join
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);

    // free the semaphore
    sem_destroy(&mutex);
    return 0;
}

您可以將所需的初始化添加為該實現的全局變量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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