2016-06-29 4 views
0

Я пытаюсь выполнить свой первый запуск с разделяемой памятью и названный семафор для синхронизации доступа к нему.Тупик с использованием именованного семафора

В моей программе было 3 процесса: родительский и два ребенка, все должны использовать одну и ту же общую память. для синхронизации между ними я использую named sempahore. ресурс, которым они делятся, представляет собой массив целых чисел, когда array [0] - местоположение флага выхода, которое дочерний процесс считывает до того, как они работают, чтобы определить, хочет ли родительский процесс выйти. массив [1], массив [2] - используются для связи с родительским процессом, каждый процесс помещает сообщение в свою собственную ячейку массива, а родительский процесс читает его и помещает сообщение ACK в ответ.

Я пытаюсь получить основной рабочий поток моего кода - сделайте все необходимые ресурсы, сделайте родительский сон в течение 3 секунд, а затем инициируйте exit_procedure.

Моя проблема в том, когда добраться до exit_procedure, основные технологические блоки навсегда на sem_wait() операции - видимо тупик. Я пытаюсь понять проблему и, похоже, не могу ее указать. Я новичок в синхронизации процессов - пока этот код не синхронизировал потоки.

UPDATE: Я переключился с использованием сопоставления памяти POSIX, и теперь у меня такая же проблема взаимоблокировки. соответствующие методы в process_api.h не могут захватить блокировку, они просто блокируются навсегда. Я не знаю, что я делаю неправильно. Может ли кто-нибудь помочь?

Мой код:

основной файл:

int *shmem_p;  //!< Shared variable to be used across different proccesses 
int shmem_fd;  //!< Shared memory id 
sem_t *sem_p;  //!< Sempahore for syncronizing access to shared memory 

volatile sig_atomic_t done;   //!< An atomic flag to signal this process threads they are done 
volatile sig_atomic_t signal_rcvd; //!< Indication to exit procedure if a signal caused termination 

/** 
* @brief Exit procedure to be called when program is done 
*/ 
static void exit_procedure() 
{ 
    block_all_signals();   /* Block all signals - we're already existing */ 

    if(signal_rcvd == SIGTERM) { /* SIGTERM is manually raised by us when a thread terminates, thus not handled in signal handler */ 
     write(STDERR_FILENO, "Error occured - thread terminated\n", 33); 
    } 

    if(!signal_rcvd) {   /* We got here normally, or by thread termination - set done flag */ 
     done = true; 
    } 

    /* Free all relevant resources */ 
    sem_unlink("/shmemory"); 
    sem_close(sem_p); 

    munmap(shmem_p, TOTAL_PROC_NUM*sizeof(int)); 
    shm_unlink("/shmemory"); 

    sem_p = NULL; 
    shmem_p = NULL; 
} 

static void signal_handler(int sig_num) { 
    switch(sig_num) { 
    case SIGCHLD: 
     write(STDERR_FILENO, "Error occured - Child process terminated\n", 43); 
     break; 

    case SIGALRM: 
     write(STDOUT_FILENO, "Successfully finished sim\n", 28); 
     break; 

    default: 
     fprintf(stderr, "Error - Signal %s has been raised", strsignal(sig_num)); 
     fflush(stderr); 
     break; 
    } 

    done = true; 
    signal_rcvd = true; 
} 

static status_t init_procedure() 
{ 
    done = false; 
    signal_rcvd = false; 
    size_t size = TOTAL_PROC_NUM*sizeof(int); 

    /* Initialize shared memory to be used as an exit flag to be used by all processes */ 

    shmem_fd = shm_open("/shmemory", O_CREAT | O_TRUNC | O_RDWR, 0644); 
    if(shmem_fd < 0) { 
     error_and_exit("shm_open() failed, err = ", errno); 
    } 

    if(ftruncate(shmem_fd, size)) { 
     shm_unlink("/shmemory"); 
     error_and_exit("ftruncate() failed, err = ", errno); 
    } 

    shmem_p = (int *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmem_fd, 0); 
    if(shmem_p == MAP_FAILED) { 
     shm_unlink("/shmemory"); 
     error_and_exit("mmap() failed, err = ", errno); 
    } 

    close(shmem_fd); /* No longer needed */ 
    memset(shmem_p, 0, size); 

    /* Initialize a named sempahore for the procceses shared memory */ 
    sem_p = sem_open("/shsemaphore", O_CREAT | O_RDWR, 0644, 1); 
    if(SEM_FAILED == sem_p) { 
     error("sem_open() failed, err = ", errno); 
     munmap(shmem_p, size); 
     shm_unlink("/shmemory"); 
    } 

    /* Initialize memory access invokers processes */ 
    if(processes_init() != SUCCESS) { 
     error("init_processes() failed\n", ERR); 
     munmap(shmem_p, size); 
     shm_unlink("/shmemory"); 
     sem_close(sem_p); 
     return FAILURE; 
    } 

    /* Handle Signals - Ignore SIGINT, SIGQUIT, handle SIGCHLD & SIGALRM */ 

    struct sigaction sig_handler; 
    sig_handler.sa_flags = 0; 

    if(sigfillset(&sig_handler.sa_mask)) { /* Mask all other signals inside the handler */ 
     error("sigemptyset() failed, err = ", errno); 
     exit_procedure(); 
     return FAILURE; 
    } 

    sig_handler.sa_handler = signal_handler; 
    if(sigaction(SIGCHLD, &sig_handler, NULL) || sigaction(SIGALRM, &sig_handler, NULL)) { /* Set the signal handler for SIGCHLD & SIGALRM */ 
     error("sigaction() failed, err = ", errno); 
     exit_procedure(); 
     return FAILURE; 
    } 

    sig_handler.sa_handler = SIG_IGN; 
    if(sigaction(SIGINT, &sig_handler, NULL) || sigaction(SIGQUIT, &sig_handler, NULL)) { /* Ignore ctrl+c and ctrl+z */ 
     error("sigaction() failed, err = ", errno); 
     exit_procedure(); 
     return FAILURE; 
    } 

    return SUCCESS; 
} 

int main(int argc, char *argv[]) 
{ 
    if(argc != 1) { 
     fprintf(stderr, "usage: %s (no arguments allowed)\n", argv[0]); 
     exit(EXIT_FAILURE); 
    } 

    if(SUCCESS != init_procedure()) { 
     error_and_exit("init_procedure() failed\n", ERR); 
    } 

    sleep(5); 
    exit_procedure(); 

    return EXIT_SUCCESS; 
} 

процесс обработчика:

#define WR_RATE (0.8)    //!< Writing probabilty when invoking memory access 
#define WR_RATE_INT (WR_RATE*10) //!< WR_RATE as an int value between 1 and 10 
#define INTER_MEM_ACCS_T (100000) //!< Waiting time between memory accesses 

static pid_t child_pids[CHILD_PROC_NUM]; 

int process_cnt;     //!< Determines the index of the process, for child processes 
extern sem_t *sem_p; 

static bool is_ack_received(int *mem_p, off_t size) 
{ 
    bool ack; 

    /*********************************************************/ 
    /**     Critical Section start    **/ 
    if((sem_wait(sem_p) != 0) && (errno != EINTR)) { 
     munmap(mem_p, size); 
     shm_unlink("/shmemory"); 
     error_and_Exit("sem_wait() failed, err = ", errno); 
    } 

    ack = (mem_p[process_cnt] == MSG_ACK); 

    if(ack) {// TODO - Remove 
     fprintf(stdout, "Process %d received ACK\n", process_cnt); 
     fflush(stdout); 
    } 

    if((sem_post(sem_p) != 0) && (errno != EINTR)) { 
     munmap(mem_p, size); 
     shm_unlink("/shmemory"); 
     error_and_Exit("sem_post() failed, err = ", errno); 
    } 
    /**     Critical Section end    **/ 
    /*********************************************************/ 

    return ack; 
} 

static void invoke_memory_access(int *mem_p, off_t size) 
{ 
    msg_e send_msg = MSG_READ; 
    if(rand_range(1, 10) <= WR_RATE_INT) { /* Write Memory */ 
     send_msg = MSG_WRITE; 
    } 

    /*********************************************************/ 
    /**     Critical Section start    **/ 
    if((sem_wait(sem_p) != 0) && (errno != EINTR)) { 
     munmap(mem_p, size); 
     shm_unlink("/shmemory"); 
     error_and_Exit("sem_wait() failed, err = ", errno); 
    } 

    mem_p[process_cnt] = send_msg; 
    fprintf(stdout, "Process %d sent MSG_%d in mem_address: %p\n", process_cnt, send_msg, &mem_p[process_cnt]); // TODO - Remove 
    fflush(stdout); 

    if((sem_post(sem_p) != 0) && (errno != EINTR)) { 
     munmap(mem_p, size); 
     shm_unlink("/shmemory"); 
     error_and_Exit("sem_post() failed, err = ", errno); 
    } 
    /**     Critical Section end    **/ 
    /*********************************************************/ 
} 

static void main_loop() 
{ 
    int shmem_fd = shm_open("/shmemory", O_RDWR, 0); 
    if(shmem_fd < 0) { 
     error_and_Exit("shm_open() failed, err = ", errno); 
    } 

    struct stat mem_stat; 
    fstat(shmem_fd, &mem_stat); 

    int *child_memory_p = (int *)mmap(NULL, mem_stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmem_fd, 0); 
    if(child_memory_p == MAP_FAILED) { 
     shm_unlink("/shmemory"); 
     error_and_Exit("mmap() failed, err = ", errno); 
    } 

    close(shmem_fd); /* No longer needed */ 

    bool first_run = true; 
    bool ack = false; 
    const struct timespec ns_wait = {.tv_sec = 0, .tv_nsec = INTER_MEM_ACCS_T}; 

    while(child_memory_p[0] != MSG_EXIT) { 
     if(!first_run) {     /* Not the first run, check for ack */ 
      ack = is_ack_received(child_memory_p, mem_stat.st_size); 
     } 

     nanosleep(&ns_wait, NULL); 

     if(!first_run && !ack) { /* No ack received for latest call, nothing to be done */ 
      continue; 
     } 

     invoke_memory_access(child_memory_p, mem_stat.st_size); 

     if(first_run) {    /* First run is over.. */ 
      first_run = false; 
     } 
    } 

    fprintf(stdout, "PROCCESS %d EXIT!\n", process_cnt); // TODO Remove this 
    fflush(stdout); 

    munmap(child_memory_p, mem_stat.st_size); 
    shm_unlink("/shmemory"); 

    child_memory_p = NULL; 

    _Exit(EXIT_SUCCESS); 
} 

status_t processes_init() 
{ 
    pid_t pid; 
    process_cnt = 1; /* Will be used for child processes to determine their order creation */ 
    int i; 
    for(i = 0; i < CHILD_PROC_NUM; ++i) { 
     pid = fork(); 

     if(ERR == pid) { 
      error("fork() failed, err = ", errno); 
      return FAILURE; 
     } else if(pid != 0) {   /* Parent process */ 
      child_pids[i] = pid; 
      process_cnt++; 
     } else {      /* Child process */ 
      block_all_signals();  /* Only main process responsible for indicate exit to its child*/ 
      main_loop(); 
     } 
    } 

    return SUCCESS; 
} 

void processes_deinit(int **mem_p) 
{ 
    (*mem_p)[0] = MSG_EXIT; 
    fprintf(stdout, "EXIT wrriten to address %p\n", *mem_p); 

    /* Wait for all child processes to terminate */ 
    int i; 
    write(STDOUT_FILENO, "Waiting for children to exit\n", 29); // TODO Remove this 
    for(i = 0; i < CHILD_PROC_NUM; ++i) { 
     if((ERR == waitpid(child_pids[i], NULL, 0)) && (ECHILD != errno)) { 
      error("waitpid() failed, err = ", errno); 
     } 
    } 

    fprintf(stdout, "PROCCESS DEINIT DONE!\n"); // TODO Remove this 
    fflush(stdout); 
} 

Может кто-то пожалуйста, объясните, что я я делаю неправильно?

Я пробовал:

  1. передавая sem_t указателя из основного процесса, как * sem_t ** semaphore_p * до processes_init метода, и каждый ребенок использовать реальный указатель на семафор (даже если ребенок будет копировать указатель на КПС mecanishm, он будет по-прежнему использовать фактические Благодарности Адресной

  2. декларирования sem_t указатель как экстерн в обработчике процесса

  3. Открытие каждого ребенка процесс (в main_loop метод) "копию" в имени семафора с помощью sem_open ("/ shsemaphore", O_RDWR)

Ни один из них работал.я схожу с ума над здесь, ребята, пожалуйста, помогите мне :(

ответ

1

Решение найдено:.

При создании имени семафор в главном файле, разрешения были установлены в 0644, , который дал группе процессов только разрешение на чтение.

После перехода на следующее:

sem_open(semaphore_name, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 1) 

Проблема, кажется, решена! Очевидно, что если sem_wait вызывается без чтения/записи разрешений на семафоре (что происходило в дочернем процессе - они использовали семафор только с разрешениями READ), поведение не определено

2

В функции init_procedure() после открытия семафора, есть вызов функции

sem_unlink(shared_sem_name); 

, который всегда выполняется, сразу разрушив семафор . после его создания вы хотите эту строку в блоке обработки ошибок

+0

, который сделал трюк. Я думал, что sem_unlink только отменит само имя, ожидая, пока все дочерние процессы выйдут, прежде чем уничтожить семафор. Более интересно - как получилось ** sem_wait ** просто заблокировано и не возвращает ошибку с * errno *, установленным в EINVAL ?? – Adiel

+0

EINVAL будет иметь больше смысла здесь. Команды sem_unlink/sem_wait не совсем ясны в этом вопросе, но я предполагаю, что структура sem_t, которую указывает shared_sem_name, не определена после sem_unlink() (т.е. что-то может быть там, и ей больше нельзя доверять), и что это блок памяти по-прежнему составляет действительную структуру семафора. – Sander

+0

После переключения на сопоставление памяти posix (но все еще используется sem_open и т. Д.) Проблема сохраняется, к сожалению, В надежде, может, у вас есть другая идея? – Adiel