2015-05-09 2 views
1

В настоящее время я пытаюсь реализовать одну программу на C, которая создает область разделяемой памяти для данного процесса, а затем переводит этот процесс в один дочерний элемент, заставляет ребенка записывать в заданную позицию разделяемой памяти и отец ждет до тех пор, пока ребенок не напишет в этом положении. Я использовал простой оживленный подход, страдающий родительским процессом, чтобы подождать, пока ребенок закончит писать, используя цикл while. Проблема в том, что он работает только при введении некоторой задержки в этом цикле. Кто-нибудь знает, почему это так?Занятое ожидание и общая память

Код:

int shmid; 
int *shmptr; 
int i, j, ret; 

key_t key = SHM_KEY; 

// Create shared memory segment 
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0600)) < 0) 
{ 
    printf("shmget error: %s\n", strerror(errno)); 
    return -1; 
} 

// Attach shared memory segment 
if ((shmptr = shmat(shmid, 0, 0)) == (void *) -1) 
{ 
    puts("shmat error"); 
    return -1; 
} 

shmptr[6] = '%'; 

ret = fork(); 
if (ret > 0) 
{/*parent*/ 
    /*here is the loop that implements the busy waiting approach*/ 
    while (shmptr[6] != '^') { 
     sleep(1); 
    } 
    for (i = 0; i < 7; i++) printf("%c", shmptr[i]); 
    puts(""); 

    int status = 0; 
    wait(&status); 
} 
else 
{/*child*/ 
    shmptr[0] = 's'; 
    shmptr[1] = 'h'; 
    shmptr[2] = 'a'; 
    shmptr[3] = 'r'; 
    shmptr[4] = 'e'; 
    shmptr[5] = 'd'; 

    /*tell parent process ithas finished its writing*/ 
    shmptr[6] = '^'; 

    exit(0); 
} 
+0

Как объявляется shmptr? В частности, неустойчиво ли это? – DoxyLover

+0

Можете ли вы уточнить свой код ИЛИ разместить весь код? –

+0

"* Он работает только тогда, когда я ввожу некоторую задержку в этот цикл *« что происходит без задержки? – alk

ответ

0

Вы хотите synchonise доступ к памяти акций (ГИМ).

Это, например, может быть выполнено с использованием semphore.

  1. До fork() С дочернего вызова sem_open().
  2. Перед тем, как читать SHM, родитель должен подождать sem_wait().
  3. Попросите ребенка позвонить sem_post() после завершения ввода SHM.
0

Я думаю, что происходит то, что ребенок заканчивается слишком быстро.

Вы можете использовать не висящие waitpid(2) и добавить его в цикле:

/*here is the loop that implements the busy waiting approach*/ 
int status= 0; 
while (shmptr[6] != '^') { 
    if (waitpid(ret, &status, WNOHANG) == ret) break; 
    sleep(1); 
} 

Однако, как я заметил, занят ждет это всегда плохо в Linux программ пространства пользователя (по крайней мере, это подчеркивает вашу систему). Прочтите sem_overview(7) или, альтернативно, настройте pipe(7) или eventfd(2) или signalfd(2) и poll(2). Или настройте обработчик сигнала SIGCHLD (внимательно прочитайте signal(7)), который просто устанавливает флаг volatile sigatomic_t для проверки в вашем цикле.

Вы также должны объявить volatile int*shmptr;, потому что компилятор мог бы оптимизировать его использование.

1

Неустойчивость (см. Предыдущий комментарий, вероятно, будет работать только в одноядерном сценарии). Предполагая, что вы работаете на процессоре с несколькими ядрами, вам нужно будет обрабатывать доступ каждого местоположения в области разделяемой памяти атомарно. Если использовать компилятор, совместимый с C++ 11, каждое местоположение области должно быть принято иметь тип std::atomic<int>.

Поскольку вы, вероятно, используете C, а не C++, и используете GCC, рассмотрите возможность использования атомных встроенных функций GCC Atomic Builtins.

Итак, ваш

shmptr[0] = 's'; 

заявление должно быть заменено с атомным оператором множества:

_sync_val_compare_and_swap(&shmptr[0], 's'); 

И сделать эквивалент для всех множеств. Затем выполните эквивалент в цикле, чтобы проверить возвращаемое значение (которое будет вашим символом).

Семафор в другом ответе может работать, но нет никаких гарантий того, что другие местоположения будут выполнены через схему записи с использованием центрального процессора через контроллер кэша на источнике и т. Д. Через контроллер принимающего ЦП , особенно если к адресам, к которым осуществляется доступ, относятся строки кэш-памяти.

Я бы также рекомендовал делать сон (0) или yield(), чтобы другие программы могли получать временные фрагменты в ядре, на котором работает основная программа, иначе вы будете тратить ресурсы процессора.

Смежные вопросы