Difference between revisions of "Process Race (Prova pratica 18-07-2013)"
Jump to navigation
Jump to search
Line 200: | Line 200: | ||
==Soluzione di Claudio Kerov == | ==Soluzione di Claudio Kerov == | ||
+ | Questa è la versione dell'esercizio 1 senza sincronizzazione della partenza dei processi. | ||
+ | |||
<source lang="c"> | <source lang="c"> | ||
Latest revision as of 07:36, 30 March 2015
Esercizio 1: Linguaggio C (obbligatorio): (20 punti)
Una gara fra processi.
Scrivere un programma C che prenda in input (da standard input) alcune righe contenenti comandi con relativi parametri. La lista dei comandi termina quando viene inserita una riga vuota.
A questo punto tutti i comandi vengono eseguiti in modo concorrente e deve venir stampato l'ordine di terminazione.
(E' vietato usare system, popen o simili)
Es.
$ prorace
sleep 30
sleep 10
sleep 20
ls -l
input di una riga vuota .... output di ls -l ....
1 arrivato: ls -l
2 arrivato: sleep 10
3 arrivato: sleep 20
4 arrivato: sleep 30
Esercizio 2: completamento (10 punti)
Si estenda l'esercizio 1 in modo da avere una partenza piu' sincronizzata dei processi.
Tutti i processi devono attendere un evento che li sblocchi tutti insieme, per esempio tutti i processi possono mettersi in
attesa con poll o select sul canale di lettura di una pipe. Quando “prorace” scrive un carattere sulla pipe tutti i processi diventano ready.
Soluzione di Federico Giuggioloni
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <poll.h>
#include <string.h>
struct list_el
{
pid_t pid;
char* comando;
struct list_el* next;
};
void insert_el(struct list_el** head, char* command, pid_t id)
{
struct list_el *new_el = malloc(sizeof(struct list_el));
new_el->comando = malloc(sizeof(char) * strlen(command) + 1);
strcpy(new_el->comando, command);
new_el->next = NULL;
new_el->pid = id;
if(*head == NULL)
{
*head = new_el;
}
else
{
struct list_el* tmp = (*head)->next;
(*head)->next = new_el;
new_el->next = tmp;
}
}
int strspl(char*** split, char* string, const char* delim)
{
char* result;
char* parsed = malloc(strlen(string)+1);
char* tofree = parsed;
int size = 2;
char* ptr = string;
while(*ptr != 0)
{
if(*ptr == *delim) size++;
ptr++;
}
if(*split == NULL)
{
*split = malloc(sizeof(char*) * size);
}
strcpy(parsed, string);
int i = 0;
while((result = strtok(parsed, delim)) != NULL)
{
//subsequent calls to strtok must have NULL in the first
//parameter
parsed = NULL;
//(*split)[i] = result;
(*split)[i] = malloc(strlen(result) * sizeof(char) + 1);
strcpy((*split)[i], result);
i++;
}
(*split)[i] = (char*) 0;
free(tofree);
return i;
}
struct list_el* head = NULL;
char* printNamePid(pid_t pid)
{
struct list_el* p = head;
while(p != NULL)
{
if(p->pid == pid) return p->comando;
p = p->next;
}
}
int main(int argc, char* argv[])
{
int n;
char *string;
string = NULL;//malloc(MAX_BUFF * sizeof(char));
int bytes_read;
pid_t pid;
char** splitargs = NULL;
char delim = ' ';
int nFork = 0;
int err;
int pipe_read = 0;
char pipe_char = ' ';
int pipefd[2];
pipe(pipefd);
struct pollfd pipe_read_poll;
pipe_read_poll.fd = pipefd[0];
pipe_read_poll.events = POLLIN;
while((bytes_read = getline(&string, &n, stdin)) != 0)
{
if(strcmp(string, "\n") == 0) break;
string[strlen(string)-1] = 0;
strspl(&splitargs, string, &delim);
pid = fork();
switch(pid)
{
case -1:
printf("Error fork: %s (%d)", strerror(errno), errno);
exit(2);
break;
case 0:
//pipe_read = read(pipefd[0], &pipe_read, 1);
poll(&pipe_read_poll, 1, -1);
err = execvp(splitargs[0], splitargs);
if(err < 0)
{
printf("Error exec: %s (%d)", strerror(errno), errno);
exit(1);
}
exit(0);
break;
default: //PADRE, continua pure
nFork++;
insert_el(&head, string, pid);
break;
}
//free(splitargs); //TODO anche di tutte le stringhe all'interno
splitargs = NULL;
}
int status = 0;
char buf = 'g';
char* comando = NULL;
int ordineArrivo[nFork];
int i = 0;
write(pipefd[1], &buf, 1);
while(i < nFork)
{
pid = wait(&status);
ordineArrivo[i] = pid;
i++;
}
printf("\n\n");
for(i = 0; i < nFork; i++)
{
comando = printNamePid(ordineArrivo[i]);
printf("%d : %s Terminated\n", i, comando);
}
return 0;
}
Soluzione di Claudio Kerov
Questa è la versione dell'esercizio 1 senza sincronizzazione della partenza dei processi.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
struct lista{
struct lista *next;
char* stringa;
};
void leggiArgomenti(char* comando) //prendo il comando dalla stringa, la divido in programma e argomenti, poi la eseguo
{
char* temp;
char delim= ' ';
char* args[64]; //alla fine uso questo
char** next = args; //ma questo e' quello che riempio
temp= strtok(comando, &delim );
while (temp != NULL)
{
*next++ = temp;
temp = strtok(NULL, &delim);
}
*next = NULL;
execvp(args[0], args);
}
void ins(struct lista *l, char* comando)
{
struct lista *tmp = malloc(sizeof(struct lista));
tmp->stringa = malloc(sizeof(char)*strlen(comando)+1);
tmp->next= l->next;
strcpy(tmp->stringa, comando);
l->next = tmp;
}
int main (int argc, char *argv[])
{
size_t n;
int status = 0;
char *riga= (char*)malloc(sizeof(char));
struct lista *lista_arrivi=(struct lista*) malloc(sizeof(struct lista));
struct lista *tmp = lista_arrivi;
lista_arrivi->next = NULL;
while( (getline(&riga, &n, stdin)!=0))
{
if (strcmp(riga, "\n")==0)
break;
ins(lista_arrivi, riga);
counter++;
}
while(lista_arrivi!=NULL)
{
pid_t pid = fork();
switch(pid)
{
case -1: exit(2);
break;
case 0: //processo figlio che prende in input i comandi
leggiArgomenti(lista_arrivi->stringa);
break;
default: //processo padre che stampera' la lista
lista_arrivi= lista_arrivi->next;
break;
}
}
tmp = tmp->next;
while(tmp!=NULL)
{
wait(&status);
printf("Terminato: %s\n", tmp->stringa);
tmp= tmp->next;
}
return 0;
}