Problem wzajemnego wykluczania z użyciem semaforów

0

Witam ponownie. Jestem w trakcie pisania programu związanego z problemem wzajemnego wykluczania. Niestety, mimo iż program został napisany wg algorytmu, który znalazłem, proces proces.x w ogóle nie wchodzi do sekcji krytycznej. Prosiłbym o podpowiedź, gdzie należy szukać błędu, co zostało napisane nie tak. Przyznaję, że średnio rozumiem temat semaforów. Poniżej zamieszczam kod:

powielacz.c - tworzy zadaną przez użytkownika liczbę procesów (drugi argument wywołania) w oparciu o nazwę pliku (pierwszy argument):

#include "func.h"
#define BASE 0          //trzeci argument funkcji strtol
#define PATH_SIZE 25    //maksymalna długość ścieżki
#define PN_WSK 2        //przesunięcie wskaźnika na tablicę path
#define FIRST_CHARS "./"
#define VAL 1

int main(int argc, char const *argv[])
{
    if (argc<3) //liczba argumentow wywolania
    {
        perror("Zbyt mala liczba argumentow wywolania!\nProsze uruchomic program ponownie, z wlasciwa liczba arugmentow.\n");
        exit(6);
    }
    
    const int syg_nr=strtol(argv[2], NULL, BASE);   //liczba procesów
    char path[PATH_SIZE]=FIRST_CHARS;  //ścieżka poprzedzona znakami "./"
    int key;    //klucz
    int id_sem; //ID zbioru

    if(syg_nr==-1)  //błędny pierwszy argument
    {
        perror("Blad funkcji strtol()\n");
        exit(8);
    }

    if(syg_nr<=1)   //błędny drugi argument
    {
        perror("Liczba procesow musi byc wieksza niż 1!\nProsze o ponowne uruchomienie programu z poprawnym parametrem.\n");
        exit(6);
    }

    if(sscanf(argv[1], "%s", path+PN_WSK)==-1)  //pierwszy argument
    {
        perror("Blad funkcji sscanf()\n");
        exit(7);
    }
    
    key=semAccess();        //uzyskanie dostępu
    id_sem=createSem(key);  //utworzenie zbioru
    setValue(id_sem, VAL);  //przypisanie wartości

    for(int i=1; i<=syg_nr; i++)
    {
        const int child_pid=fork();

        if(child_pid==-1)
        {
            fprintf(stderr, "Nie udalo sie utworzyc procesu potomnego o numerze: %d.\n", i);
            exit(9);
        }
        else if(child_pid==0)
        {
            if(execl(path, argv[1], NULL)==-1)
            {
                perror("Blad funkcji exec()\n");
                exit(10);
            }            
        }
        sleep(4);
    }

    semDelete(id_sem);

    return 0;
}

proces.c - program, który wrzucam do powielacza:

#include "func.h"
#define LOOP_TM 5   //liczba wejść do sekcji krytycznej

int main(int argc, char const *argv[])
{
    key_t key;  //klucz do zbioru semaforów
    const int pid=getpid(); //ID procesu
    int id_sem; //ID zbioru semaforów

    key=semAccess();    //uzyskanie klucza do zbioru semaforów
    id_sem=createSem(key);  //utworzenie zbioru

    for(int i=1; i<=LOOP_TM; i++)
    {
        down(id_sem);
        printf("Proces o ID: %d uzyskal dostep do sekcji krytycznej po raz: %d\n", pid, i);
        sleep(1);
        printf("Proces o ID: %d opuszcza sekcje krytyczna po raz: %d\n", pid, i);
        up(id_sem);
        sleep(1);
        printf("Proces o ID: %d przeszedl do sekcji reszty po raz: %d\n", pid, i);
    }
    //5-krotne przejście procesu do sekcji krytycznej
    //oraz wyjście z niej
    //zgodnie z algorytmem zamieszczonym w materiałach

    printf("Proces %d opuscil petle...\n", pid);    //komunikat końcowy procesu

    return 0;
}

func.c:

#include "func.h"
#define SEM_NR 1            //liczba semaforów
#define MODE 0666           //tryb
#define SEM0 0              //nr semafora w zbiorze
#define PATH "./proces.x"   //ścieżka pliku dla funkcji ftok()

int createSem(key_t key)
{
    int semid;
    semid=semget(key, SEM_NR, IPC_CREAT|IPC_EXCL|MODE);
    //if(==-1);
    //{
      //  perror("Blad funkcji createSem()\n");
        //exit(4);
    //}
    return semid;
}

void setValue(int semid, int val)
{
    union semun ctrl;
    ctrl.val=val;
    if(semctl(semid, SEM0, SETVAL, ctrl)==-1)  //SETVAL orzymuje wartość 1
    {
        perror("Blad funkcji setValue()\n");
        exit(5);
    }
}

void up(int semid)
{
    struct sembuf do_op = {0, 1, 0};
    //struktura zawiera kolejno: nr semafora, operację, flagę
    //czyli: semnum, sem_op, sem_flg
    //0 - operacja blokująca
    if(semop(semid, &do_op, SEM_NR)==-1)
    {
        perror("Blad funkcji up()\n");
        exit(2);
    }
}

void down(int semid)
{
    struct sembuf do_op = {0, -1, 0};
    if(semop(semid, &do_op, SEM_NR)==-1)
    {
        perror("Blad funkcji down()\n");
        exit(2);
    }
}

void semDelete(int semid)   //usuwanie semafora
{
    if(semctl(semid, SEM0, IPC_RMID)==-1)   //obsługa błędów
    {
        perror("Blad funkcji semDelete\n");
        exit(1);
    }
    else    //komunikat
    {
        printf("Semafor zostal usuniety\n");
    }
}

key_t semAccess()   //uzyskanie dostępu do semafora
{
    int key;
    if((key=ftok(PATH, getpid()))==-1)
    {
        perror("Blad funkcji semAccess()\n");
        exit(3);
    }
    return key;
}

func.h:

#ifndef FUNC_H
#define FUNC_H

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>

#ifdef _SEM_SEMUN_UNDEFINED

union semun {
int val;				    //wartosc dla SETVAL
struct semid_ds *buf;	    //bufor dla IPC_STAT, IPC_SET
unsigned short *array;	    //tablica dla GETALL, SETALL
struct seminfo *__buf;	    //bufor dla IPC_INFO (specyfika Linuksa)
};

#endif  //_SEM_SEMUN_UNDEFINED

int createSem(key_t key);   //utworzenie semafora
void setValue(int semid, int val);   //przypisanie wartośći (inicjalizacja)
void up(int semid);         //podniesienie semafora...
void down(int semid);       //...i jego opuszczenie
key_t semAccess();          //dostęp do semafora
//int queue(int semid);       //kolejka
void semDelete(int semid);  //usunięcie semafora

#endif  //FUNC_H

W func.c funkcja createSem() miała mieć obsługę błędów, ale gdy ją dodaję, kompilator ostrzega o warunku, który nie chroni, a program zwraca błąd: "Blad funkcji createSem(): Success".

1

Masz poprawiony kod co nieco. Generalnie problem był z tym, że niepotrzebnie dawałeś 0660.

#include "func.h"
#define SEM_NR 1			//liczba semaforów
#define MODE 0600		   //tryb
#define SEM0 0			  //nr semafora w zbiorze
#define PATH "./proces.x"   //ścieżka pliku dla funkcji ftok()

int
createSem(key_t key, int flags)
{
	int semid;

	semid = semget(key, SEM_NR, flags);
	if (semid == -1) {
		perror("Blad funkcji createSem()\n");
		exit(4);
	}
	return semid;
}

void
setValue(int semid, int val)
{
	union semun ctrl;

	ctrl.val = val;
	if (semctl(semid, SEM0, SETVAL, ctrl) == -1) {
		perror("Blad funkcji setValue()\n");
		exit(5);
	}
}

void
up(int semid)
{
	struct sembuf do_op = {
		.sem_num = 0,
		.sem_op = 1,
		.sem_flg = 0
	};

	if (semop(semid, &do_op, SEM_NR) == -1) {
		perror("Blad funkcji up()\n");
		exit(2);
	}
}

void
down(int semid)
{
	struct sembuf do_op = {
		.sem_num = 0,
		.sem_op = -1,
		.sem_flg = 0
	};

	if (semop(semid, &do_op, SEM_NR) == -1) {
		perror("Blad funkcji down()\n");
		exit(2);
	}
}

void
semDelete(int semid)
{

	if (semctl(semid, SEM0, IPC_RMID) == -1) {
		perror("Blad funkcji semDelete\n");
		exit(1);
	}
	else {
		printf("Semafor zostal usuniety\n");
	}
}

key_t
semAccess()
{
	key_t key;
	key = ftok(PATH, 1);
	if (key == -1) {
		perror("Blad funkcji semAccess()\n");
		exit(3);
	}
	return key;
}
#include <sys/types.h>
#include <sys/wait.h>

#include <errno.h>
#include "func.h"
#define BASE 0		  //trzeci argument funkcji strtol
#define PATH_SIZE 255	//maksymalna długość ścieżki
#define VAL 1

int
main(int argc, char *argv[])
{
	int nchildren;
	char *endptr;
	int key;
	int id_sem;

	if (argc < 3) {
		fprintf(stderr, "Zbyt mala liczba argumentow wywolania!\nProsze uruchomic program ponownie, z wlasciwa liczba arugmentow.\n");
		exit(1);
	}

	nchildren = strtol(argv[2], &endptr, 10);
	if (*endptr != '\0' || errno == EINVAL) {
		fprintf(stderr, "Invalid number: %s\n", argv[2]);
		exit(2);
	}

	if (nchildren <= 1) {
		fprintf(stderr, "Liczba procesow musi byc wieksza niż 1!\nProsze o ponowne uruchomienie programu z poprawnym parametrem.\n");
		exit(4);
	}

	key = semAccess();
	id_sem = createSem(key, IPC_CREAT | SEM_R | SEM_A);
	setValue(id_sem, VAL);

	for(int i; i < nchildren; i++)
	{
		const int pid = fork();

		if (pid == -1) {
			fprintf(stderr, "Nie udalo sie utworzyc procesu potomnego o numerze: %d.\n", i);
			exit(9);
		} else if (pid == 0) {
			if (execlp(argv[1], argv[1], NULL) == -1) {
				perror("Blad funkcji exec()\n");
				exit(10);
			}
		}
		sleep(4);
	}

	for (int i = 0; i < nchildren; i++) {
		pid_t child;
		int status;

		child = wait(&status);
		printf("Child %d finished with code %d\n", child, status);
	}

	semDelete(id_sem);

	return 0;
}
#include "func.h"
#define LOOP_TM 5   //liczba wejść do sekcji krytycznej

int
main(int argc, char *argv[])
{
	key_t key;  //klucz do zbioru semaforów
	const int pid = getpid(); //ID procesu
	int id_sem; //ID zbioru semaforów

	key = semAccess();	//uzyskanie klucza do zbioru semaforów
	id_sem = createSem(key, IPC_CREAT | SEM_R | SEM_A);  //utworzenie zbioru

	for (int i = 1; i <= LOOP_TM; i++) {
		down(id_sem);
		printf("Proces o ID: %d uzyskal dostep do sekcji krytycznej po raz: %d\n", pid, i);
		sleep(1);
		printf("Proces o ID: %d opuszcza sekcje krytyczna po raz: %d\n", pid, i);
		up(id_sem);
		sleep(1);
		printf("Proces o ID: %d przeszedl do sekcji reszty po raz: %d\n", pid, i);
	}
	//5-krotne przejście procesu do sekcji krytycznej
	//oraz wyjście z niej
	//zgodnie z algorytmem zamieszczonym w materiałach

	printf("Proces %d opuscil petle...\n", pid);	//komunikat końcowy procesu

	return 0;
}
#ifndef FUNC_H
#define FUNC_H
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
 
#ifdef _SEM_SEMUN_UNDEFINED
 
union semun {
int val;                    //wartosc dla SETVAL
struct semid_ds *buf;       //bufor dla IPC_STAT, IPC_SET
unsigned short *array;      //tablica dla GETALL, SETALL
struct seminfo *__buf;      //bufor dla IPC_INFO (specyfika Linuksa)
};
 
#endif  //_SEM_SEMUN_UNDEFINED
 
int createSem(key_t key, int flags);   //utworzenie semafora
void setValue(int semid, int val);   //przypisanie wartośći (inicjalizacja)
void up(int semid);         //podniesienie semafora...
void down(int semid);       //...i jego opuszczenie
key_t semAccess();          //dostęp do semafora
//int queue(int semid);       //kolejka
void semDelete(int semid);  //usunięcie semafora
 
#endif  //FUNC_H

0

@kapojot: Wielkie dzięki. Mógłbyś mi jeszcze wyjaśnić, co oznaczają flagi SEM_R oraz SEM_A? Nigdzie nie mogę znaleźć informacji na ich temat.

1

Dostęp do semafora R/W dla użytkownika i grupy. https://www.freebsd.org/cgi/man.cgi?query=semget&sektion=2

0

Jeszcze raz wielkie dzięki :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1