Esercizio 1 Prova Pratica 25-09-2014
Jump to navigation
Jump to search
'''Esercizio 1'''
Scrivere un programma che preso come parametro un file contenente un elenco di comandi (con I relativi parametri)
li attivi tutti in esecuzione concorrente e rimanga in attesa. Quando il primo termina, vengono terminati (con segnale SIGTERM) tutti gli altri.
(consiglio: puo' essere utile usare la mia libreria s2argv-execs)
esempio:
wta commands
il file commands contiene:
./ttest 40
./ttest 10
./ttest 20
lo script ./ttest contiene:
#!/bin/bash
echo waiting for $1 seconds
sleep $1
echo done $i
l'ouptut sara':
waiting for 40 seconds
waiting for 10 seconds
waiting for 20 seconds
done 10
e poi basta perche' gli altri processi verranno terminati.
Soluzione di Stefano Zaniboni
#include <stdio.h>
#include <s2argv.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <error.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <poll.h>
int main(int argc, char *argv[]){
FILE *stream;
char *line=NULL;
size_t len=0;
ssize_t read;
int i=0;
int status;
pid_t fineFirst; /*memorizzo il pid del primo processo terminato*/
pid_t all[i];
int pipefd[2];
struct pollfd pipe_read_poll;
if(argc!=2){
fprintf(stderr,"Argomento Mancante!\n");
exit(1);
}
stream=fopen(argv[1], "r");
if(stream == NULL)
exit(EXIT_FAILURE);
/*aprire una pipe, dentro al while dove ho la fork fare poll che aspetta un carattere dalla pipe. Lo mando finito il while*/
pipe(pipefd);
pipe_read_poll.fd = pipefd[0];
pipe_read_poll.events = POLLIN;
while((read = getline(&line, &len, stream)) != -1) {
if(fork()==0){
i++;
char **lines=s2argv(line, NULL);
poll(&pipe_read_poll,1,-1);
execvp(lines[0], lines);
all[i]=getpid(); /**/
s2argv_free(lines);
perror("execvp fail!");
exit(1);
}
else
exit(2);
}
/*inviare carattere alla pipe*/
char buf='g';
write(pipefd[1], &buf, 1);
fineFirst=wait(&status);
/*kill the rest of process*/
while(i > 0){
if(all[i] != fineFirst){
kill(all[i], SIGTERM);
}
--i;
}
fclose(stream);
exit(0);
}
'''Esercizio 2'''
Completare wta in modo che l'output di ogni comando venga salvato separatemente e solo l'output del processo terminato per
primo venga mostrato.
Nell'esempio di prima l'output dovra' essere:
waiting for 10 seconds
done 10
Soluzione di Maldus
#include <s2argv.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
int main(int argc, char* argv[]){
int i=0, status, out;
FILE *fd, *output;
pid_t *idents, winner;
char *line=NULL, *string;
size_t n=1;
int pipefd[2];
pipe(pipefd);
struct pollfd pipepoll;
pipepoll.fd = pipefd[0];
pipepoll.events = POLLIN;
if( !(fd = fopen(argv[1], "r"))){
perror("fopen:");
exit(1);
}
while( getline(&line, &n, fd) > 0){
i++;
free(line);
line=NULL;
}
idents = malloc(sizeof(pid_t)*i);
rewind(fd);
i = 0;
while( getline(&line, &n, fd) >0 ){
switch( idents[i]=fork()){
case 0:
asprintf( &string, "out%i" ,getpid());
if( (out=open(string, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR)) <0){
perror("open");
exit(1);
}
free(string);
dup2(out, 1);
close(out);
poll(&pipepoll, 1, -1);
execsp(line);
exit(0);
default:
free(line);
line=NULL;
i++;
break;
}
}
write(pipefd[1], "g", 1);
winner = wait(&status);
i--;
for( ; i >= 0 ; i--){
if(idents[i]!=winner){
kill(idents[i], SIGTERM);
asprintf( &string, "out%i", idents[i]);
unlink(string);
free(string);
}
}
asprintf( &string, "out%i" , winner);
if( !(output = fopen(string, "r"))){
perror("fopen");
exit(1);
}
while( getline(&line, &n, output)>0){
printf("%s", line);
free(line);
line=NULL;
}
unlink(string);
fclose(fd);
fclose(output);
return 0 ;
}
Per stampare solo l'output del processo vincente salvo quello di ciascun processo in un file di testo ( che poi cancello ). Mi viene però da pensare che debba esistere un modo migliore per farlo...