• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

System V semafory (C) - dwóch pisarzy, jeden czytelnik

Object Storage Arubacloud
0 głosów
295 wizyt
pytanie zadane 29 grudnia 2020 w Systemy operacyjne, programy przez niezalogowany
przywrócone 29 grudnia 2020

Witam, mam do napisania dwa programy, jeden z nich to pisarz, drugi to czytelnik. Pisarzy może być dwóch co czytelnik musi obsłużyć. Pisanie będzie się odbywać do jednej pamięci współdzielonej. Pisarze czytają z plików typu /etc/group, /etc/profile podawanych jako parametr przy uruchamianiu programu. Czytelnik odczytuje z pamięci napis i wyświetla ją na ekran oraz zapisuje do pliku odpowiadającego danemu pisarzowi. Wszystko ma być zsynchronizowane za pomocą semaforów. Poniżej wklejam kod obu programów, niestety nie wiem w jaki sposób sprawić, żeby działały one poprawnie.

pisarz.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/ipc.h>

#define NAZWA_PLIKU "pisarz.c"
#define ROZMIAR_PAMIECI 130

void podnies(int numer, int id);
void opusc(int numer, int id);

int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		fprintf(stderr, "Niepoprawna liczba argumentow!\n");
		exit(EXIT_FAILURE);
	}
	
	FILE *plikWejsciowy = fopen(argv[1], "r");
	if (plikWejsciowy == NULL)
		exit(EXIT_FAILURE);
	
	key_t klucz = ftok(NAZWA_PLIKU, 'r');
	if (klucz == -1)
		exit(EXIT_FAILURE);
		
	int idPamiec = shmget(klucz, ROZMIAR_PAMIECI * sizeof(char), 0666 | IPC_CREAT);
	char *pamiec = (char *)shmat(idPamiec, NULL, 0);
	
	int idSemafor = semget(IPC_PRIVATE, 2, 0666 | IPC_CREAT);
	semctl(idSemafor, 0, SETVAL, 1);
    semctl(idSemafor, 1, SETVAL, 0);
    
    FILE *plikSemafor = fopen("semid1", "r");
    if (plikSemafor == NULL)
    {
		plikSemafor = fopen("semid1", "w");
		if (plikSemafor == NULL)
			exit(EXIT_FAILURE);
		
		fprintf(plikSemafor, "%d %d", idSemafor, getpid());
		fclose(plikSemafor);
	}
	else
	{
		fclose(plikSemafor);
		
		plikSemafor = fopen("semid2", "r");
		if (plikSemafor == NULL)
		{
			plikSemafor = fopen("semid2", "w");
			if (plikSemafor == NULL)
				exit(EXIT_FAILURE);
				
			fprintf(plikSemafor, "%d %d", idSemafor, getpid());
			fclose(plikSemafor);
		}
		else
			fclose(plikSemafor);
	}
    
	char linia[ROZMIAR_PAMIECI];
	while (fgets(linia, ROZMIAR_PAMIECI, plikWejsciowy) != NULL)
	{
		opusc(0, idSemafor);
		sprintf(pamiec, "%d %s", getpid(), linia);
		puts(linia);
		podnies(1, idSemafor);
	}
	
	opusc(0, idSemafor);
	strcpy(pamiec, "koniec");
	podnies(1, idSemafor);
	
	shmdt(pamiec);
	shmctl(idPamiec, IPC_RMID, NULL);
	semctl(idSemafor, 0, IPC_RMID);
	
	return 0;
}

void podnies(int numer, int id)
{
	struct sembuf sem;
	
	sem.sem_num = numer;
	sem.sem_op = 1;
	sem.sem_flg = 0;
	semop(id, &sem, 1);
}

void opusc(int numer, int id)
{
	struct sembuf sem; 
	
	sem.sem_num = numer; 
	sem.sem_op = -1;
	sem.sem_flg = 0;
	semop(id, &sem, 1);
}

czytelnik.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/ipc.h>

#define NAZWA_PLIKU "pisarz.c"
#define ROZMIAR_PAMIECI 130

void podnies(int numer, int id);
void opusc(int numer, int id);

int zwroc_pid(char *linia);

int main(void)
{
	key_t klucz = ftok(NAZWA_PLIKU, 'r');
	if (klucz == -1)
		exit(EXIT_FAILURE);
		
	int idPamiec = shmget(klucz, ROZMIAR_PAMIECI * sizeof(char), 0666 | IPC_CREAT);
	char *pamiec = (char *)shmat(idPamiec, NULL, 0);
	
	int idSemafor1, idSemafor2, pid1, pid2;
	int czyCzytac1 = 1;
	int czyCzytac2 = 0;
	
	FILE *plikSemafor = fopen("semid1", "r");
	if (plikSemafor == NULL)
		exit(EXIT_FAILURE);
	else
	{
		fscanf(plikSemafor, "%d %d", &idSemafor1, &pid1);
		fclose(plikSemafor);
		
		plikSemafor = fopen("semid2", "r");
		if (plikSemafor == NULL)
		{
			idSemafor2 = -1;
			pid2 = -1;
		}
		else
		{
			czyCzytac2 = 1;
			fscanf(plikSemafor, "%d %d", &idSemafor2, &pid2);
			fclose(plikSemafor);
		}
	}
	
	FILE *plik1 = NULL;
	FILE *plik2 = NULL;
	
	plik1 = fopen("PLIK1", "w");
	if (plik1 == NULL)
		exit(EXIT_FAILURE);
		
	if (idSemafor2 != -1)
	{
		plik2 = fopen("PLIK2", "w");
		if (plik2 == NULL)
			exit(EXIT_FAILURE);
	}
			
	int licznik1 = 0;
	int licznik2 = 0;
	while (1)
	{
		int pid = zwroc_pid(pamiec);
		
		opusc(1, idSemafor1);
		if (pid == pid1 && czyCzytac1 == 1)
		{
			if (strcmp(pamiec, "koniec") == 0)
				czyCzytac1 = 0;
				
			if (czyCzytac1 == 1)
			{
				fprintf(plik1, "%s", pamiec);
				fprintf(stdout, "%s", pamiec);
				licznik1++;
			}
		}
		podnies(0, idSemafor1);
		
		opusc(1, idSemafor2);				
		if (pid == pid2 && czyCzytac2 == 1)
		{
			if (strcmp(pamiec, "koniec") == 0)
				czyCzytac2 = 0;

			if (czyCzytac2 == 1)
			{
				fprintf(plik2, "%s", pamiec);
				fprintf(stdout, "%s", pamiec);
				licznik2++;
			}
		}
		podnies(0, idSemafor2);
		
		if (czyCzytac1 == 0 && czyCzytac2 == 0)
			break;
		
		usleep(100000);
	}
	
	printf("Do pliku PLIK1 zapisano %d linii.\n", licznik1);
	fclose(plik1);
	
	if (idSemafor2 != -1)
	{
		printf("Do pliku PLIK2 zapisano %d linii.\n", licznik2);
		fclose(plik2);
	}
	
	return 0;	
}

void podnies(int numer, int id)
{
	struct sembuf sem;
	
	sem.sem_num = numer;
	sem.sem_op = 1;
	sem.sem_flg = 0;
	semop(id, &sem, 1);
}

void opusc(int numer, int id)
{
	struct sembuf sem; 
	
	sem.sem_num = numer; 
	sem.sem_op = -1;
	sem.sem_flg = 0;
	semop(id, &sem, 1);
}

int zwroc_pid(char *linia)
{
    char *pid = (char *)malloc(sizeof(char) * 10);
    
    int i;
    for(i = 0; linia[i] != ' '; i++)
        pid[i] = linia[i];
    
    pid[i] = '\0';

    return atoi(pid);
}

 

komentarz 29 grudnia 2020 przez j23 Mędrzec (194,920 p.)
edycja 29 grudnia 2020 przez j23
int zwroc_pid(char *linia)
{
    char *pid = (char *)malloc(sizeof(char) * 10);
     
    int i;
    for(i = 0; linia[i] != ' '; i++)
        pid[i] = linia[i];
     
    pid[i] = '\0';
 
    return atoi(pid);
}

Oj, cieknie...

A można przecież tak:

int zwroc_pid(const char *linia)
{
    int pid;
    return sscanf(linia, "%i", &pid) == 1 ? pid : -1;
}

Wydaje mi się też, że powinieneś użyć klucza klucz zamiast IPC_PRIVATE przy tworzeniu semaforów, wtedy nie musiałbyś się bawić plikami (to działa w ogóle?), tylko wywołać po obu stronach semget(klucz, ...).

1 odpowiedź

0 głosów
odpowiedź 29 grudnia 2020 przez overcq Pasjonat (21,650 p.)

Program działa dla jednego pisarza z wyjątkiem wyjścia z czytelnika.

Brak jest wstawiania znaku '\0' na końcu każdej linii w pamięci współdzielonej.

Dla dwóch pisarzy podstawowym błędem jest używanie przez każdego pisarza własnych semaforów podczas zapisu do tego samego obszaru pamięci. Nadpisują sobie ten obszar pamięci, bo nie blokują się wzajemnie.

Poza tym w funkcji zwroc_pid brak zwalniania pamięci.

komentarz 30 grudnia 2020 przez niezalogowany
http://www.cplusplus.com/reference/cstdio/sprintf/

I to prawda, jednak użycie dwóch zestawów semaforów to głupi pomysł.
komentarz 30 grudnia 2020 przez overcq Pasjonat (21,650 p.)
edycja 30 grudnia 2020 przez overcq

U mnie w lokalnej dokumentacji (Linux) jest, że sprintf nie dodaje przy formacie %s znaku null, a snprintf wypisuje go niezależnie od formatu.

Podobne pytania

0 głosów
0 odpowiedzi 849 wizyt
0 głosów
0 odpowiedzi 243 wizyt
pytanie zadane 13 kwietnia 2019 w C i C++ przez hidden55 Początkujący (270 p.)
0 głosów
0 odpowiedzi 179 wizyt
pytanie zadane 8 listopada 2022 w Java przez CanoNee Nowicjusz (230 p.)

92,539 zapytań

141,382 odpowiedzi

319,479 komentarzy

61,928 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...