2015-12-24 6 views
1

Я пытаюсь создать программу в C для Unix. Учитывая массив, я должен передать каждый элемент массива из родительского процесса в его дочерний элемент через общую память и с помощью семафора. Это то, что у меня есть.Передача данных из родительского процесса в дочерний процесс - IPC, UNIX

const key_t sem_key = (key_t)0x12345611; 
const key_t shm_key = (key_t)0x12339611; 

int sem_wait(int semafor_id) 
{ 
    struct sembuf sb; 
    sb.sem_num = 0; 
    sb.sem_op = -1; 
    sb.sem_flg = SEM_UNDO; 

    return semop(semafor_id, &sb, 1); 
} 

int sem_signal(int semafor_id) 
{ 
    struct sembuf sb; 
    sb.sem_num = 0; 
    sb.sem_op = 1; 
    sb.sem_flg = SEM_UNDO; 

    return semop(semafor_id, &sb, 1); 
} 

int main(int argc, char *argv[]) 
{ 
    int status; 
    char str[3]; 
    str[0] = 'z'; 
    str[1] = 'x'; 
    str[2] = 'y'; 

    // Create shared memory 
    int memory_id = shmget(shm_key, 1, 0600 | IPC_CREAT | IPC_EXCL); 
    if (memory_id < 0) 
    { 
     printf("Shared memory creating failed\n"); 
     return 1; 
    } 

    // Create semafor 
    int semafor_id = semget(sem_key, 10, 0600 | IPC_CREAT | IPC_EXCL); 
    if (semafor_id < 0) 
    { 
     printf("SEMAFOR creating failed\n"); 
     return 1; 
    } 
    semctl(semafor_id, 0, SETVAL, 1); // init semafor 

    pid_t pid = fork(); 
    if (pid < 0) 
     printf("FORK FAILED\n"); 

    else if (pid > 0) 
    { 
     printf("PARENT\n"); 
     void *address = shmat(memory_id, NULL, 0); 
     if (address == NULL) 
     { 
      printf("Failed to attach memory\n"); 
      return 1; 
     } 
     if (sem_wait(semafor_id) < 0) // sem_wait() decrements (locks) the semaphore pointed to by sem. 
     { 
      printf("Failed wait parent\n"); 
      return 1; 
     } 

     for (int i = 0; i < 3; i++) 
     { 
      void *address = shmat(memory_id, NULL, 0); 
      if (address == NULL) 
      { 
       printf("Failed to attach memory\n"); 
       return 1; 
      } 
      printf("writer started.\n"); 
      char *data = (char *) address; 
      *data = str[i]; 
      printf("writer ended.\n"); 
     } 

     if (shmdt(address) != 0) 
      printf("Failed to detach shared memory\n"); 

     if (sem_signal(semafor_id) < 0) 
      printf("Failed signal parent\n"); 
     else 
      printf("Parent leave generating number\n"); 


     // wait for child 
     wait(&status); 
     printf("Destroy semafor\n"); 
     semctl(semafor_id, 0, IPC_RMID, 0); 
     printf("Destroy shared memory\n"); 
     shmctl(memory_id, IPC_RMID, 0); 

     return 0; 
    } // close parent case 
    else 
    { 
     printf("CHILD\n"); 
     if (sem_wait(semafor_id) < 0) 
      printf("FAILED wait child\n"); 
     else 
     { 
      void *address = shmat(memory_id, NULL, 0); 
      if (address == NULL) 
      { 
       printf("Failed to atach memory in child\n"); 
       return 1; 
      } 
      char *data = (char *) address; 
      printf("Child read data %c\n", *data); 

      if (shmdt(address) != 0) 
       printf("Failed to detach shared memory in child\n"); 
     } 
    } 

    if (sem_signal(semafor_id) < 0) 
     printf("Failed signal child\n"); 
    else 
     printf("Leave data reading\n"); 

    return 0; 
} 

токовый выход заключается в следующем:

writer started 
writer ended 
writer started 
writer ended 
writer started 
writer ended 
child read data y 
destroy semafor 
destroy shared memory 

Как вы можете увидеть родительскую запись в общей памяти в 3 раза, а затем ребенок получить доступ к общей памяти печати данные совместно Память. Выход я хотел бы иметь это:

writer started 
writer ended 
child read data z 
writer started 
writer ended 
child read data x 
writer started 
writer ended 
child read data y 
destroy semafor 
destroy shared memory 
+0

снимка экрана не нужна, вы можете просто скопировать/вставить, как вы сделали с вашим желаемым результатом. Просто назовите его как «текущий выход». Удачи. – shellter

+0

С этим кодом существует несколько проблем. Это домашняя задача? Что именно вам непонятно? – fukanchik

ответ

2

Проблема заключается в логике. После удаления шаблонного кода, логика выглядит следующим образом:

Get shared memory 
Get semaphore with value 1 
fork 
in parent: 
    wait semaphore (problem #1, #2) <-- supposed to decrement it to 0 

    for(i=0;i<3;++i) 
    { 
     write next char <<-- no synchronization here :-(
    } 

    signal semaphore 

    wait for child 
    STOP 

in child: 
    wait semaphore (problem #1) 
    read next char 
    signal semaphore 
    (problem #3) 
    STOP 

на английском:

the writer acquires write lock 
writes 3 values into the same location 
then signals the reader to read data. 
At this moment writer moves on to wait for child PID to die. 

The reader reads the last value once 
signals the semaphore 
then exits. 

At this moment writer sees reader died 
cleans up 
...and exits 

Проблема # 1: родительские и дочерние процессы протекают одновременно, в то же время. Любое из них может сначала преуспеть в sem_wait. Если ребенок делает это первым, он будет распечатать тарабарское начальное неинициализированное значение из разделяемой памяти, а родительский будет заблокирован в ожидании семафора навсегда. Попробуйте добавить воображаемый (или не) сон (1) в родительский сегмент перед семафором ожидания. Это будет эмулировать переключатель контекста процессора.

Проблема №2: Вы ждете/сигнализируете только один раз. Например. вы пишете все значения и только затем сигнализируете. Именно поэтому печатается только последнее значение.

Задача № 3: у ребенка нет петель. Как он должен читать 3 значения ?!

Логика должна быть:

Writer 
    Do 3 times: 
     acquire write semaphore 
     write next value 
     signal reader semaphore 
    wait child to die 
    clean up 
    exit 

reader: 
    Do 3 times: 
     acquire reader semaphore 
     read next value 
     signal writer semaphore 
    exit 
+0

Сколько семафора мне нужно? 1 или 2 (семафор читателя и семафор писателя)? – splunk

+0

Да, из-за проблемы №1 вам нужен семафор записи и считываемый семафор. – fukanchik

+0

@ GreenMamba ничего не осталось вам неясным? – fukanchik