3

I am working on a C program that simulates a hair salon, and I'm facing an issue with terminating the main process from the simulation_timer_thread. The only way I can successfully exit the main process is by using the kill function, which is not ideal.

In my simulation_timer_thread, after displaying the message printf(RED "Simulation ended, you can exit the program.\n" RESET);, I try to use exit(EXIT_SUCCESS); to end the program, but it doesn't work as expected - the main process is still running and program is not ended - there is still existing thread (it is not a problem closing it does not really help) and one process of program.

However, I can properly terminate the program in the koniec function and in the signal handler for a quick exit. This leads me to believe that there might be something specific to how the thread is structured that's preventing the program from exiting correctly.

Could anyone help me understand why I can't exit the main process from the simulation_timer_thread using exit()? Any insights or suggestions for a better approach to handle this would be greatly appreciated!

Thank you! Sorry for half of code in polish language ;/


char menu = 0;
    while (menu != '3' /*&& !koniec_symulacji*/)
    {
        printf(CYAN "1 - Zakończ pracę fryzjera\n");
        printf("2 - Natychmiastowo zamknij salon\n");
        printf("3 - Zwolnij zasoby i zakończ program\n" RESET);

        while (getchar() != '\n')
            ; // Czeszczenie bufora
        while (scanf("%c", &menu) != 1)
            ;

        switch (menu)
        {
        case '1':
            zabij_fryzjera(); // sygnał 1 kończy pracę jednego fryzjera
            break;
        case '2':
            sig_handler_int(0); // sygnał 2 kończy natychmiastowo pracę wszystkich klientów
            break;
        case '3':
            koniec(0); // zamyka program, zwalniając ps i ipcs
            break;
        default:
            printf(RED "Niepoprawna opcja\n" RESET);
            break;
        }
    }
    // pthread_join(timer_thread, NULL);
    // return 0;
}
...
void *simulation_timer_thread(void *arg)
{
    if (TP > 0)
    {
        sleep(TP); // Jeśli TP (czas opóźnienia otwarcia salonu) > 0, czekamy przez TP sekundy - domyślnie sleep(TP)
    }
    printf(YELLOW "Salon otwarty.\n" RESET);                                                                   // Informacja o otwarciu salonu
    sem_setval(poczekalnia_semafor, K);                                                                        // Inicjalizacji poczekalni - ilość K wolnych miejsc
    printf(YELLOW "Zainicjalizowano poczekalnię, ilość miejsc: %d.\n" RESET, sem_getval(poczekalnia_semafor)); // Informacja o inicjalizacji poczekalni

    int remaining = sim_duration; // Zmienna do przechowywania czasu pozostałego do zakończenia symulacji
    while (remaining > 0)         // Pętla działa dopóki nie minie czas symulacji
    {
        printf(MAGENTA "Czas pozostały: %d s\n", remaining); // Informacja o pozostałym czasie
        sleep(1);                                            // Symulacja upływu czasu - MUSI BYĆ USTAWIONY CZAS 1
        remaining--;                                         // Zmniejszenie liczby pozostałych sekund
    }
    sem_setval(poczekalnia_semafor, 0); // NALEŻY ZAKOMENTOWAĆ GDY SLEEP(0) Zamknięcie poczekalni po upływie czasu - równoznaczne z zamknięciem salonu - kolejni klienci nie wejdą
    printf(YELLOW "Salon zamknięty.\n" RESET);
    zabij_klientow();
    zabij_fryzjerow();
    zwolnij_zasoby_kierownik();
    printf(RED "Symulacja zakończona można zakończyć program.\n" RESET);
    // koniec_symulacji = 1;
    //  pthread_cancel(timer_thread);
    //   pthread_join(timer_thread, NULL);
    //   exit(EXIT_SUCCESS);
    // return NULL;
    //   kill(getpid(), SIGKILL);
}

void zabij_klientow()
{
    for (int i = 0; i < P; i++) // zabicie wszystkich klientów
    {
        kill(klienci[i], 2); // 2 - SYGNAŁ SIGINT
    }
    wait_for_process(P);
}

void zabij_fryzjerow()
{
        for (int i = 0; i < F; i++) // zabicie wszystkich fryzjerów
        {
            kill(fryzjerzy[i], 1); // 1 - SYGNAŁ SIGHUP
        }
        wait_for_process(F);
}

void zwolnij_zasoby_kierownik() // funkcja zwalniająca wszelkie zasoby
{
    //deleting semaphores, shared memory and message queue
    usun_kolejke_komunikatow(msg_qid);
    usun_semafor(kasa_semafor);
    usun_semafor(fotele_semafor);
    usun_semafor(poczekalnia_semafor);
    odlacz_pamiec_dzielona(kasa);
    usun_pamiec_dzielona(shm_id);
    printf(YELLOW "Zasoby zwolnione\n" RESET);
}

Link to whole file if needed: https://github.com/bartekzadlo/SO_Salon_Fryzjerski/blob/main/kierownik.c

What I found is that the process is waiting for input: strace -p 7486 strace: Process 7486 attached read(0,

To resolve this issue, I tried:

Using pthread_cancel and pthread_join: I attempted to cancel the timer thread and then join it in the main function, but this did not effectively terminate the main process.

4
  • Having at least some code helps, but a MRE such as I requested (in the Staging Ground) is a complete program, as small as possible, that we can build and run ourselves to reproduce the issue. I appreciate that it is not trivial to prepare one, but remember that that's a debugging exercise itself. You may even discover the issue yourself that way. We ask for a reproducible example because people bringing debugging problems are notoriously bad about judging what parts of their code are relevant. We ask for minimal because our time is valuable, even if we're giving it to you for free. Commented Feb 26 at 6:09
  • I note also that exit() can be called from any thread to terminate a program. It's unclear why that is not working for you, but exit() does perform some cleanup, so perhaps it's getting stuck there. Figuring that out is precisely the kind of thing for which a MRE is important. Commented Feb 26 at 6:16
  • 1
    The whole file is not needed. What is needed is a minimal reproducible example, where both minimal and reproducible parts are important. Commented Feb 26 at 6:44
  • exit() is a nightmare. _exit() on any reasonable system is immediate terminate; exit() can literally do anything, and with a corrupted image [ seems to be your problem ] only makes matters worse. Commented Feb 27 at 5:15

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.