Witam. Jestem w trakcie zmagań z problemem producenta i konsumenta. Jako rozwiązanie używam semaforów zliczających, pamięci dzielonej oraz bufora cyklicznego. Niestety, po uruchomieniu oba procesy dość szybko się zatrzymują, pomaga jedynie ich ubicie. W pliku wynikowym pojawia się od jednej do trzech liter + śmietnik lub plik jest pusty. Już od dłuższego czasu próbuję dojść do ładu z tym programem, pisałem sekcje krytyczne od zera, ale to nic nie dało. Kompletnie nie wiem, co jest źle. Proszę o pomoc, poradę. Poniżej załączam pliki programu.
main.c:
#include "mem_func.h"
#include "sem_func.h"
#define SIZE 25
int main(int argc, char const *argv[])
{
const char prod_path[]="./producer.x";
const char prod_name[]="producer.x";
const char cons_path[]="./consumer.x";
const char cons_name[]="consumer.x";
const int wait_val=2;
if(argc<1)
{
perror("Za malo argumentow\n");
exit(8);
}
const key_t sem_key=createSem();
const int id_sem=semAccess(sem_key);
const key_t mem_key=memCreate();
const int mem_id=memAccess(mem_key, sizeof(Towar));
const int producer=fork();
char semid[SIZE];
char memid[SIZE];
sprintf(semid, "%d", id_sem);
sprintf(memid, "%d", mem_id);
if (producer==-1)
{
perror("Nie udalo sie utworzyc procesu producenta\n");
exit(6);
}
else if(producer==0)
{
if(execl(prod_path, prod_name, semid, memid, argv[3], NULL)==-1)
{
perror("Nie udalo sie uruchomic procesu producenta\n");
exit(7);
}
}
//sleep(SLV);
const int consumer=fork();
if (consumer==-1)
{
perror("Nie udalo sie utworzyc procesu konsumenta\n");
exit(6);
}
else if(consumer==0)
{
if(execl(cons_path, cons_name, semid, memid, argv[4], NULL)==-1)
{
perror("Nie udalo sie uruchomic procesu kosumenta\n");
exit(7);
}
}
//sleep(SLV);
for (int i=0; i<wait_val; ++i)
{
int status;
const pid_t child=wait(&status);
printf("Proces o ID: %d zakonczyl prace z kodem: %d\n", child, status);
}
semDelete(id_sem, VAL2);
//semDelete(id_sem, SEM1);
memDel(mem_id);
return 0;
}
producer.c:
#include "mem_func.h"
#include "sem_func.h"
int main(int argc, char const *argv[])
{
const int id_sem=atoi(argv[1]);
const int mem_id=atoi(argv[2]);
char buf[BUF_SIZE];
const int file1=open(argv[3], O_RDONLY, 0644);
if(file1==-1)
{
perror("Blad funkcji open() - proc. producenta\n");
exit(9);
}
Towar *bufor;
bufor=(Towar*) memAtt(mem_id, O_WRONLY);
/*bufor[0].begin=0;
bufor[0].end=0;*/
//setValue(id_sem, SEM0, VAL);
//int bytes_read=0;
//int bytes_written=0;
bufor->begin=0;
bufor->end=0;
int counter=0;
while(read(file1, buf, sizeof(buf)))
{
setValue(id_sem, SEM0, (EMPTY-counter));
for(int i=0; i<(strlen(buf)+1); ++i)
{
down(id_sem, SEM0);
bufor->share[bufor->end]=buf[i];
++bufor->end;
printf("Producent:\n");
printf("%c\n", buf[i]);
if(bufor->end==50)
bufor->end=0;
up(id_sem, SEM1);
}
++counter;
if(counter==50)
{
sleep(1);
counter=0;
}
}
down(id_sem, SEM0);
bufor->share[bufor->end]='~';
up(id_sem, SEM1);
if(close(file1)==-1)
{
perror("Blad funkcji close() - proces producenta\n");
exit(11);
}
delAtt(bufor);
return 0;
}
consumer.c:
#include "mem_func.h"
#include "sem_func.h"
int main(int argc, char const *argv[])
{
const int id_sem=atoi(argv[1]);
const int mem_id=atoi(argv[2]);
char buf[BUF_SIZE];
const int file2=open(argv[3], O_WRONLY|O_CREAT, 0644);
if(file2==-1)
{
perror("Blad funkcji open() - proc. konsumenta\n");
exit(9);
}
Towar *bufor;
bufor=(Towar*) memAtt(mem_id, O_RDONLY);
char read;
bufor->begin=0;
bufor->end=0;
//setValue(id_sem, SEM1, VAL);
//int bytes_read=0;
//int bytes_written=0;
int counter=0;
while(1)
{
setValue(id_sem, SEM1, (FULL+counter));
down(id_sem, SEM1);
read=bufor->share[bufor->begin];
if(read=='~')
{
++bufor->begin;
if(bufor->begin==50)
{
bufor->begin=0;
}
down(id_sem, SEM0);
}
printf("Konsument:\n");
printf("%c"-'\0', read);
if(write(file2, &read, (sizeof(read)))==-1)
{
perror("Blad zapisu do pliku\n");
exit(10);
}
++counter;
if(counter==50)
{
sleep(1);
counter=0;
}
++bufor->begin;
if(bufor->begin==50)
{
bufor->begin=0;
}
up(id_sem, SEM1);
}
if(close(file2)==-1)
{
perror("Blad funkcji close() - proces konsumenta\n");
exit(11);
}
delAtt(bufor);
return 0;
}
sem_func.c:
#include "sem_func.h"
#define SEM_NR 2 //liczba semaforów
#define MODE 0600 //tryb
#define PATH "./main.x" //ścieżka pliku dla funkcji ftok()
int semAccess(key_t key)
{
int semid;
semid=semget(key, SEM_NR, IPC_CREAT|MODE);
if(semid==-1)
{
perror("Blad funkcji semAccess()\n");
exit(4);
}
return semid;
}
void setValue(int semid, int nsem, int val)
{
union semun ctrl;
ctrl.val=val;
if(semctl(semid, nsem, SETVAL, ctrl)==-1) //SETVAL orzymuje wartość 1
{
perror("Blad funkcji setValue()\n");
exit(5);
}
}
void up(int semid, int nsem)
{
struct sembuf do_op = {
.sem_num=nsem,
.sem_op=1,
.sem_flg=0
};
//struktura zawiera kolejno: nr semafora, operację, flagę
//czyli: semnum, sem_op, sem_flg
//0 - operacja blokująca
if(semop(semid, &do_op, VAL)==-1)
{
perror("Blad funkcji up()\n");
exit(2);
}
}
void down(int semid, int nsem)
{
struct sembuf do_op = {
.sem_num=nsem,
.sem_op=-1,
.sem_flg=0
};
if(semop(semid, &do_op, VAL)==-1)
{
perror("Blad funkcji down()\n");
exit(2);
}
}
void semDelete(int semid, int nsem) //usuwanie semafora
{
if(semctl(semid, nsem, IPC_RMID)==-1) //obsługa błędów
{
perror("Blad funkcji semDelete\n");
exit(1);
}
else //komunikat
{
printf("Semafor zostal usuniety\n");
}
}
key_t createSem() //uzyskanie dostępu do semafora
{
int key;
if((key=ftok(PATH, 'a'))==-1)
{
perror("Blad funkcji createSem()\n");
exit(3);
}
return key;
}
mem_func.c:
#include "mem_func.h"
int memCreate()
{
const int key=ftok(PATH, 'b');
if(key==-1)
{
perror("Blad funkcji memCreate\n");
exit(12);
}
return key;
}
int memAccess(int key, int size)
{
const int mem_id=shmget(key, size, IPC_CREAT|IPC_EXCL|MODE);
if(mem_id==-1)
{
perror("Blad funkcji memAccess\n");
exit(13);
}
return mem_id;
}
void memDel(int mem_id)
{
struct shmid_ds buf;
if(shmctl(mem_id, IPC_RMID, (struct shmid_ds*)0)==-1)
{
perror("Blad funkcji memDel()\n");
exit(14);
}
else printf("Usunieto pamiec dzielona\n");
}
void *memAtt(int mem_id, int mode)
{
void *shm=shmat(mem_id, NULL, mode);
if(shm==(void*)-1)
{
fprintf(stderr, "Blad funkcji memAtt()\n");
exit(15);
}
else printf("Utworzono dowiazanie\n");
return shm;
}
void delAtt(void *shm)
{
if(shmdt(shm)==-1)
{
fprintf(stderr, "Blad funkcji delAtt()\n");
exit(16);
}
else printf("Usunieto dowiazanie\n");
}
int memSize(int mem_id)
{
struct shmid_ds x;
if(shmctl(mem_id, IPC_STAT, &x)==-1)
{
perror("Blad funkcji memSize()\n");
exit(17);
}
return x.shm_segsz;
}
sem_func.h:
//biblioteka dla semaforów
#ifndef SEM_FUNC_H
#define SEM_FUNC_H
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <time.h>
#define EMPTY 50
#define FULL 0
#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
enum {SEM0, SEM1, VAL=1, VAL2, SLV=5};
int semAccess(key_t key); //utworzenie semafora
void setValue(int semid, int nsem, int val);
//przypisanie wartośći (inicjalizacja)
void up(int semid, int nsem); //podniesienie semafora...
void down(int semid, int nsem); //...i jego opuszczenie
key_t createSem(); //dostęp do semafora
//int queue(int semid); //kolejka
void semDelete(int semid, int nsem); //usunięcie semafora
#endif //FUNC_H
mem_func.h:
//biblioteka dla pamięci dzielonej
#ifndef MEM_FUNC_H
#define MEM_FUNC_H
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define PATH "./consumer.x"
#define MODE 0600
#define MEM_SIZE 50
#define BUF_SIZE 50
typedef struct
{
char share[MEM_SIZE];
int begin;
int end;
} Towar;
int memCreate(); //tworzenie pamięci dzielonej
int memAccess(int key, int size); //dostęp do pamięci dzielonej
void memDel(int mem_id); //usuwanie pamięci dzielonej
void *memAtt(int mem_id, int mode); //tworzenie dowiązania
void delAtt(void *mem_id); //usuwanie dowiązania
int memSize(int mem_id); //rozmiar pamięci dzielonej
#endif
EDIT: Poprawiłem jeden znaleziony przeze mnie błąd. Został on także poprawiony w powyższym kodzie. Teraz program zachowuje się różnie, ale zawieszanie się pozostało. Teraz plik wyjściowy jest albo niezdatny do odczytu, albo zawiera najwyżej kilkanaście słów + śmieci.
Program dostaje zwiechy po ok. 50 znakach, czyli tyle, ile wynosi wielkość bufora.