2016-06-29 16 views
0

Ich versuche meinen ersten Lauf mit Shared Memory und benannte Semaphor, um den Zugriff darauf zu synchronisieren.Deadlock mit dem Namen Semaphor

Mein Programm hatte 3 Prozesse - Eltern 1 und zwei Kinder, alle müssen den gleichen gemeinsamen Speicher verwenden. Um zwischen ihnen zu synchronisieren, verwende ich namens Sempahore. die Ressource, die sie teilen, ist ein 3 Ganzzahlen-Array, wenn Array [0] - Exit-Flag-Position, die der Kindprozess gelesen, bevor sie arbeiten, um festzustellen, ob Elternprozess beenden möchte. Array [1], Array [2] - werden verwendet, um mit dem übergeordneten Prozess zu kommunizieren, jeder Prozess platziert eine Nachricht in seiner eigenen Array-Zelle und der übergeordnete Prozess liest sie und platziert eine ACK Nachricht in respone.

Ich versuche, einen grundlegenden Arbeitsablauf meines Codes zu bekommen - mache alle notwendigen Ressourcen, mache Elternschlaf für 3 Sekunden und initiiere dann den exit_procedure.

Mein Problem ist, wenn sie auf die exit_procedure bekommen, die wichtigsten Prozessblöcke für immer auf sem_wait() -Operation - scheinbar Sackgasse. Ich versuche, das Problem zu lösen und kann nicht darauf hinweisen. Ich bin neu in der Prozess-Synchronisation - bis zu diesem Code habe ich nur Threads synchronisiert.

UPDATE: Ich habe mit POSIX Memory Mapping geschaltet, und jetzt habe ich das gleiche Deadlock-Problem. Relevante Methoden in process_api.h können die Sperre nicht erreichen, sie blockieren nur für immer. Ich weiß nicht, was ich falsch mache. Können einige bitte helfen?

Mein Code:

Hauptdatei:

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; 
} 

Prozess Handler:

#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); 
} 

Kann jemand bitte erklären, was ich falsch mache?

Ich habe versucht:

  1. sem_t Zeiger vom Hauptprozess als * sem_t ** semaphore_p * zu processes_init Methode übergeben, und hat jedes Kind den realen Zeiger auf den Semaphore verwenden (Selbst wenn das Kind den Zeiger auf COW mecanishm kopieren wird, wird er immer noch den tatsächlichen addres Dank verwenden

  2. deklarieren der sem_t Zeiger als extern in der Prozess Handler

  3. Öffnen jedes Kind Prozess (in der main_loop-Methode) eine "Kopie" des genannten Semaphore mit sem_open ("/ shsemaphore", O_RDWR)

Nichts davon gearbeitet.Ich gehe hier Jungs verrückt, bitte helft mir :(

Antwort

1

Lösung gefunden.

Wenn in Hauptdatei mit dem Namen Semaphore erstellen, auf 0644 Berechtigungen festgelegt wurden, die der Prozessgruppe nur Leseberechtigung erteilt.

Nach dem folgenden Wechsel:

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

scheint das Problem gelöst zu werden! Offenbar, wenn sem_wait aufgerufen wird, ohne Lese-/Schreibberechtigungen für den Semaphor (was im Kindprozess passiert ist - sie haben den Semaphor nur mit READ-Berechtigung verwendet), ist das Verhalten nicht definiert

2

In der Funktion init_procedure() nach der Semaphore Öffnen gibt es einen Funktionsaufruf

sem_unlink(shared_sem_name); 

, die immer dann ausgeführt wird, die Semaphore zu zerstören sofort . nach seiner Gründung Sie mögen diese Zeile in der Fehlerbehandlung Block

+0

. Ich dachte, sem_unlink entkoppelt nur den Namen selbst und wartet darauf, dass alle untergeordneten Prozesse beendet werden, bevor der Semaphor gelöscht wird. Interessanter - wie kommt es, dass ** sem_wait ** gerade blockiert wird und kein Fehler mit * errno * auf EINVAL ?? – Adiel

+0

EINVAL wäre hier sinnvoller. Die Hilfeseiten sem_unlink/sem_wait sind nicht genau klar, aber meine Vermutung ist, dass die sem_t-Struktur, auf die shared_sem_name zeigt, nach sem_unlink() undefiniert ist (dh alles kann da drin sein und es sollte nicht länger vertrauenswürdig sein), und dies Speicherblock bildet immer noch eine gültige Semaphorstruktur. – Sander

+0

Nach dem Wechsel zu posix Speicherabbildung (aber immer noch mit sem_open etc) bleibt das Problem leider In der Hoffnung, Sie haben vielleicht eine andere Idee? – Adiel