Discussione Ufficiale Programmiamo con Inforge | Esercitazione 03 in C | Livello intermedio

Una Discussione Ufficiale punta a raccogliere tutte le informazioni su un argomento o un fatto di attualità, con costanti aggiornamenti da parte del creatore e dei partecipanti.

Not an engineer

Moderatore
31 Ottobre 2011
2,715
100
1,204
1,091
Ultima modifica:
main.png


Programmiamo con Inforge | Presentazione

Ad oggi, sul web, si trovano moltissime guide sui vari linguaggi di programmazione e sulle loro molteplici applicazioni. Tuttavia, chi si approccia a queste risorse, non sempre riesce a mettere in pratica ciò che ha appreso. Al fine di limitare queste mancanze, nasce Programmiamo con Inforge.

In questa rubrica potrai scrivere codice per la risoluzione di alcuni problemi legati alla programmazione, mettendo in pratica quanto stai apprendendo dalla teoria oppure mostrando le tue abilità e competenze nel campo dell’informatica.


Partiamo dalle basi del C

In questa guida puoi trovare i testi per studiare e approfondire il C: I migliori libri per imparare e approfondire il C
In questa discussione puoi trovare le risposte alle domande più frequenti su come scrivere codice in C: Frequently asked questions: da dove si parte?


Esercitazione 03 in C | Livello intermedio | [Programmazione concorrente]

La concorrenza è una caratteristica dei sistemi di elaborazione nei quali può verificarsi che un insieme di processi o sotto-processi sia in esecuzione nello stesso istante (un'importante classe di sistemi informatici nei quali gli aspetti di concorrenza sono fondamentali è quella dei sistemi operativi)
L'esercitazione si compone di 5 esercizi nei quali ti sarà richiesto di compiere delle operazioni base su thread e processi mediante l'utilizzo di funzioni come pid() e fork()




Soluzioni

Per rendere l'esercitazione più interessante, non verrà pubblicata alcuna soluzione! Spetterà a te scrivere la tua versione del codice e pubblicarla in questo thread così che possa essere valutata dai moderatori e dalla community; il modo migliore per imparare!

Conclusioni

Pubblica la soluzione ottimale per risolvere gli esercizi e ricorda che puoi confrontarti con il resto della community in questo thread, chiedere aiuto o aiutare gli altri ;)
 
C:
#Esercizio 1


#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define CHILD_PID 0
#define FAILED_FORK -1

int main()
{
    int pid = fork();
    if (pid == FAILED_FORK)
    {
        puts("[!] Fork call failed");
        exit(EXIT_FAILURE);
    }
    if (pid == CHILD_PID)
    {

        printf("[*] Child process id: %ld\n", (long)getpid());
    }
    else
    {
        printf("[*] Parent process id: %ld\n", (long)getpid());
    }
}

C:
#Esercizio 2

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

#define CHILD_PID 0
#define FAILED_FORK -1

static void check_fork_succesfull_executed(pid_t pid);

int main()
{
    pid_t child_a, child_b;

    child_a = fork();
    check_fork_succesfull_executed(child_a);

    if (child_a == CHILD_PID)
    {
        /* Child A code */
        printf("[*] Child A process id: %ld\n", (long)getpid());
    }
    else
    {
        child_b = fork();
        check_fork_succesfull_executed(child_b);
        if (child_b == CHILD_PID)
        {
            /* Child B code */
            printf("[*] Child B process id: %ld\n", (long)getpid());
        }
        else
        {
            /* Parent Code */
            printf("[*] Parent process id: %ld\n", (long)getpid());
        }
    }
}

static void check_fork_succesfull_executed(pid_t pid)
{
    if (pid == FAILED_FORK)
    {
        puts("[!] Fork call failed");
        exit(EXIT_FAILURE);
    }
}

C:
#Esercizio 3

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

#define CHILD_PID 0
#define FAILED_FORK -1
#define PIPE_READ_END 0
#define PIPE_WRITE_END 1
#define FAILED_PIPE_CREATION -1

static void check_fork_succesfull_executed(pid_t pid);
static void check_pipe_succesfull_created(int pipe_code);

int main()
{
    pid_t child_a;
    int pipe_fd[2];

    // create pipe
    int pipe_creation_code = pipe(pipe_fd);
    check_pipe_succesfull_created(pipe_creation_code);

    child_a = fork();
    check_fork_succesfull_executed(child_a);

    if (child_a == CHILD_PID)
    {
        /* Child code */

        /* child is writer: close pipe read end */
        close(pipe_fd[PIPE_READ_END]);

        // write process id to pipe and exit
        char buffer[sizeof(pid_t)];
        pid_t c_pid = getpid();
        sprintf(buffer, "%d", c_pid);
        write(pipe_fd[PIPE_WRITE_END], buffer, sizeof(pid_t));
        exit(EXIT_SUCCESS);
    }
    else
    {
        /* Parent Code */

        /* parent is reader: close write end */
        close(pipe_fd[PIPE_WRITE_END]);

        // read process id from pipe and print it
        char buffer[sizeof(pid_t)];
        ssize_t read_bytes = read(pipe_fd[PIPE_READ_END], buffer, sizeof(pid_t));

        printf("[*] I'm parent process %d and i got child pid: %s\n", getpid(), buffer);
    }
    exit(EXIT_SUCCESS);
}

static void check_fork_succesfull_executed(pid_t pid)
{
    if (pid == FAILED_FORK)
    {
        puts("[!] Fork call failed");
        exit(EXIT_FAILURE);
    }
}

static void check_pipe_succesfull_created(int pipe_code)
{
    if (pipe_code == FAILED_PIPE_CREATION)
    {
        puts("[!] Pipe creation failed");
        exit(EXIT_FAILURE);
    }
}

C:
#Esercizio 4


#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define CHILD_PID 0
#define FAILED_FORK -1
#define PIPE_READ_END 0
#define PIPE_WRITE_END 1
#define FAILED_PIPE_CREATION -1

static void check_fork_succesfull_executed(pid_t pid);
static void check_pipe_succesfull_created(int pipe_code);
static int ranged_rand(int lower, int upper);

int main()
{
    pid_t child_a;
    int pipe_fd[2];

    // create pipe
    int pipe_creation_code = pipe(pipe_fd);
    check_pipe_succesfull_created(pipe_creation_code);

    child_a = fork();
    check_fork_succesfull_executed(child_a);

    if (child_a == CHILD_PID)
    {
        /* Child code */

        /* child is writer: close pipe read end */
        close(pipe_fd[PIPE_READ_END]);

        // write process id to pipe and exit
        char buffer[sizeof(int)];
        int rand_0_200 = ranged_rand(0, 200);
        sprintf(buffer, "%d", rand_0_200);
        write(pipe_fd[PIPE_WRITE_END], buffer, sizeof(int));
        exit(EXIT_SUCCESS);
    }
    else
    {
        /* Parent Code */
        char buffer[sizeof(int)];

        /* parent is reader: close write end */
        close(pipe_fd[PIPE_WRITE_END]);

        // read process id from pipe and print it
        ssize_t read_bytes = read(pipe_fd[PIPE_READ_END], buffer, sizeof(int));

        printf("[*] I'm parent process %d and i got a random number in 0-200 by child: %s\n", getpid(), buffer);
    }
    exit(EXIT_SUCCESS);
}

static void check_fork_succesfull_executed(pid_t pid)
{
    if (pid == FAILED_FORK)
    {
        puts("[!] Fork call failed");
        exit(EXIT_FAILURE);
    }
}

static void check_pipe_succesfull_created(int pipe_code)
{
    if (pipe_code == FAILED_PIPE_CREATION)
    {
        puts("[!] Pipe creation failed");
        exit(EXIT_FAILURE);
    }
}

static int ranged_rand(int lower, int upper)
{
    srand(time(0));
    return (rand() % (upper - lower + 1)) + lower;
}

C:
#Esercizio 5


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

#define CHILD_PID 0
#define FAILED_FORK -1
#define PIPE_READ_END 0
#define PIPE_WRITE_END 1
#define FAILED_PIPE_CREATION -1

static void check_fork_succesfull_executed(pid_t pid);
static void check_pipe_succesfull_created(int pipe_code);
static int read_integer();

int main()
{
    pid_t child_a, child_b;
    int pipe_1_fd[2], pipe_2_fd[2];

    // open two pipes
    int pipe_1_creation_code = pipe(pipe_1_fd);
    check_pipe_succesfull_created(pipe_1_creation_code);
    int pipe_2_creation_code = pipe(pipe_2_fd);
    check_pipe_succesfull_created(pipe_2_creation_code);

    child_a = fork();
    check_fork_succesfull_executed(child_a);

    if (child_a == CHILD_PID)
    {
        /* Child A code */
        int n_0_100;
        char wrong_num_msg[] = "[!] Not a valid number in 0 100\nPlease provide one:";

        // close unused pipe ends
        close(pipe_2_fd[PIPE_WRITE_END]);
        close(pipe_2_fd[PIPE_READ_END]);
        close(pipe_1_fd[PIPE_READ_END]);

        // wait for a number
        printf("Enter a number between 0-100: ");
        do
        {
            n_0_100 = read_integer(wrong_num_msg);
            if (n_0_100 < 0 || n_0_100 > 100)
            {
                puts(wrong_num_msg);
            }
        } while (n_0_100 < 0 || n_0_100 > 100);

        // write number to pipe and exit
        char buffer[sizeof(int)];
        sprintf(buffer, "%d", n_0_100);
        write(pipe_1_fd[PIPE_WRITE_END], buffer, sizeof(int));
        exit(EXIT_SUCCESS);
    }
    else
    {
        child_b = fork();
        check_fork_succesfull_executed(child_b);
        if (child_b == CHILD_PID)
        {
            /* Child B code */

            //close unused pipes
            close(pipe_1_fd[PIPE_WRITE_END]);
            close(pipe_1_fd[PIPE_READ_END]);
            close(pipe_2_fd[PIPE_WRITE_END]);

            // read child 1 integer received from parent
            char buffer[sizeof(int)];

            ssize_t read_bytes = read(pipe_2_fd[PIPE_READ_END], buffer, sizeof(int));

            // print received buffer
            printf("I'm child two %ld and i received this number: %s\n", (long)getpid(), buffer);
            exit(EXIT_SUCCESS);
        }
        else
        {
            /* Parent Code */

            // close unused pipes
            close(pipe_1_fd[PIPE_WRITE_END]);
            close(pipe_2_fd[PIPE_READ_END]);

            // read child 1 integer from pipe
            char buffer[sizeof(int)];
            ssize_t read_bytes = read(pipe_1_fd[PIPE_READ_END], buffer, sizeof(int));
            // write it to child 2 pipe
            write(pipe_2_fd[PIPE_WRITE_END], buffer, sizeof(int));
            exit(EXIT_SUCCESS);
        }
    }
}

static void check_fork_succesfull_executed(pid_t pid)
{
    if (pid == FAILED_FORK)
    {
        puts("[!] Fork call failed");
        exit(EXIT_FAILURE);
    }
}

static void check_pipe_succesfull_created(int pipe_code)
{
    if (pipe_code == FAILED_PIPE_CREATION)
    {
        puts("[!] Pipe creation failed");
        exit(EXIT_FAILURE);
    }
}

#define READ_INT_BUF_SIZE 1024 // use 1KiB just to be sure
static int read_integer(char *wrong_int_msg)
{
    int a;
    char buf[READ_INT_BUF_SIZE];

    do
    {
        if (!fgets(buf, READ_INT_BUF_SIZE, stdin))
        {
            // reading input failed, give up:
            puts("[!] Error: cannot read input");
            return EXIT_FAILURE;
        }

        // have some input, convert it to integer:
        a = atoi(buf);
        if (a == 0)
        {
            puts(wrong_int_msg);
        }
    } while (a == 0); // repeat until we got a valid number
    return a;
}
Messaggio unito automaticamente:

Grazie per aver condiviso la soluzione!
A prima vista ben fatto direi. ;)

La prossima volta pubblicale utilizzando il tag CODE e sotto tag SPOILER, grazie. Per questa volta edito io appena riesco (tramite pc) o uno dei colleghi, se arriva prima di me.

Fatto sotto ! Aspettiamo il prossimo!
 
Provato i primi 2 unicamente seguendo una mia "logica" dato che dalle documentazioni non ho capito niente, ste cose mi pare che ce le fecero provare su linux e non avendolo disponibile al momento, non so cos'altro potrei usare. Non funzionerebbero lo stesso in ogni caso :rofl:

Codice:
E1
{
    pid_t pid1;
    pid1 = fork();

    if (pid1 < 0)
    {
      printf("\nFork non riuscito");
    }
    else if (pid1 == 0)
    {
        printf("\nPid processo figlio: %d",getpid());
        printf("\nPid processo padre: %d",getppid());
    }  
}

E2
{
    pid_t pid1, pid2;
    pid1 = fork();
  
    if(pid1<0)
    {
        printf("\nFork non riuscito");
    }
    else if (pid1 == 0)
    {
        printf("\nPid processo figlio: %d",getpid());
        printf("\nPid processo padre: %d",getppid());
        kill(getpid(), SIGKILL);
    }  
  
    pid2 = fork();
  
    if(pid2<0)
    {
        printf("\nFork non riuscito");
    }
    else if (pid2 == 0)
    {
        printf("\nPid processo figlio: %d",getpid());
        printf("\nPid processo padre: %d",getppid());
        kill(getpid(), SIGKILL);
    }
 
Puoi farlo, ma è una soluzione ad alto rischio d'errore vista la gestione dei tempi e l'eventuale utilizzo dei signal. Comunque va benissimo mandare solo il pid!
 
  • Mi piace
Reazioni: Valley
@Sax3r28
Mi sembra abbastanza corretto, non male!

Piccoli consigli per il primo esercizio
  • Prima di chiamare getpid() anteponi (int)getpid();

  • Dopo l'else-if manda a dormire il processo con sleep() o simili.
 
Ultima modifica:
@Sax3r28
Mi sembra abbastanza corretto, non male!

Piccoli consigli per il primo esercizio
  • Prima di chiamare getpid() anteponi (int)getpid();

  • Dopo l'else-if manda a dormire il processo con sleep() o simili.
Mettere int vale anche per getppid?
Sleep invece cosa dovrebbe fare di necessario? Non ritarda solo l'esecuzione?
E in caso se c'è un modo migliore per terminare un figlio :V non sapevo in che altro modo evitare che i figli ne creassero due a loro volta e li ho sterminati direttamente.
Per gli altri 3 esercizi, non so come e dove "inviare" un valore al padre e come/dove prendere questo valore. Sto leggendo cose su pipe() che mi pare serva a fare ciò (?)

Mentre mi leggo su ste pipe ti lascio una domanda: usando lo sleep() posso fare in modo che il figlio invii un sizeof() al padre e va in sleep, poi il padre salva il sizeof in una variabile, va in sleep, torno al figlio che invia il pid, lo termino e con il padre stampo quello che devo stampare? O il size di un int dichiarato è uguale a uno non dichiarato e quindi mi basta inviare solo il pid?
 
Unisco tutti i codici così si fa prima, stessa premessa sugli ultimi 3 ovvero non so come provarli e non penso di aver capito ancora tutto perfettamente.

Codice:
ES1
{
    pid_t pid1;
    pid1 = fork();

    if (pid1 < 0)
    {
      printf("\nFork non riuscito");
    }
    else if (pid1 == 0)
    {
        printf("\nPid processo figlio: %d",getpid());
        printf("\nPid processo padre: %d",getppid());
    }
}

ES2
{
    pid_t pid1, pid2;
    pid1 = fork();

    if(pid1<0)
    {
        printf("\nFork non riuscito");
    }
    else if (pid1 == 0)
    {
        printf("\nPid processo figlio: %d",getpid());
        printf("\nPid processo padre: %d",getppid());
        kill(getpid(), SIGKILL);
    }

    pid2 = fork();

    if(pid2<0)
    {
        printf("\nFork non riuscito");
    }
    else if (pid2 == 0)
    {
        printf("\nPid processo figlio: %d",getpid());
        printf("\nPid processo padre: %d",getppid());
        kill(getpid(), SIGKILL);
    }
}

ES3
{
    pid_t pid1;
    int pip1[2];
    pid1 = fork();
  

    if (pid1 < 0)
    {
      printf("\nFork non riuscito");
    }
    else if (pid1 == 0)
    {              
        close(fd[0]);
        int Rpipe;
        read(fd[0], Rpipe, (int)sizeof(Rpipe));  
        printf("\nPadre stampa PID figlio: %d",Rpipe);  
    }  
    else
    {          
        int pidF=(int)getpid();      
        write(fd1[1], pidF, (int)sizeof(pidF));  
        close(fd1[1]);
        kill((int)getpid(), SIGKILL);      
    }  
}

ES4
{
    pid_t pid1;
    int pip1[2];
    pid1 = fork();
  

    if (pid1 < 0)
    {
      printf("\nFork non riuscito");
    }
    else if (pid1 == 0)
    {              
        int Rpipe;
        read(fd[0], Rpipe, (int)sizeof(Rpipe));  
        printf("\nrand() restituisce: %d",Rpipe);  
    }  
    else
    {          
        int randF= rand() % 201;      
        write(fd1[1], randF, (int)sizeof(pidF));  
        close(fd1[1]);
        kill((int)getpid(), SIGKILL);      
    }      
}

ES5
{
    pid_t pid1, pid2;
    int pip1[2];
    int val=0;  
    pid1 = fork();
  
    if(pid1<0)
    {
        printf("\nFork non riuscito");
    }
    else if (pid1 == 0) //figlio1
    {
        printf("\nInserisci 0<valore<100: ");
        scanf("%d",&val);
        write(fd1[1], val, (int)sizeof(val));
        printf("\nFiglio1 invia valore a processo padre");
        close(fd1[1]);
        kill((int)getpid(), SIGKILL);
      
    }  
    else
    {
        int Ppipe;
        read(fd[0], Ppipe, (int)sizeof(Ppipe));  
        close(fd[0]);
        write(fd1[1], Ppipe, (int)sizeof(Ppipe));
        printf("\nPadre invia valore a figlio2");
        close(fd[1]);
        kill((int)getpid(), SIGKILL);
    }
  
    pid2 = fork();
  
    if(pid2<0)
    {
        printf("\nFork non riuscito");
    }
    else if (pid2 == 0) //figlio2
    {
        int Fpipe;
        read(fd[0], Fpipe, (int)sizeof(Fpipe));
        printf("\nFiglio2 stampa valore: %d",Fpipe);
        close(fd[0]);
      
    }  
}
 
@Sax3r28

Con sleep() hai la possibilità di sospendere il processo e di compiere altre operazioni. Non è una funziona necessaria per la risoluzione dei primi due esercizi: puoi terminare il processo e l'esecuzione del programma utilizzando exit()
Corretta l'idea di utilizzare la pipe() e la sua realizzazione con il buffer.

Per provare il tutto ti basta scrivere il programma importando le giuste librerie.

C:
// librerie utili
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int main(){
/*
codice
*/
return 0;
}
 
Ultima modifica:
Suppongo che devcpp sia troppo basico per fare certe cose allora :asd: oggi avevo provato con stdio e unistd il primo, non mi faceva usare fork e getppid.

Riguardo la domanda invece? Va "bene" come l'ho scritto o c'è un altro modo, tipo quello qua sotto?
Usando lo sleep() posso fare in modo che il figlio invii un sizeof() al padre e va in sleep, poi il padre salva il sizeof in una variabile, va in sleep, torno al figlio che invia il pid, lo termino e con il padre stampo quello che devo stampare? O il size di un int dichiarato è uguale a uno non dichiarato e quindi mi basta inviare solo il pid?
 
Visualizza allegato 51209

Programmiamo con Inforge | Presentazione

Ad oggi, sul web, si trovano moltissime guide sui vari linguaggi di programmazione e sulle loro molteplici applicazioni. Tuttavia, chi si approccia a queste risorse, non sempre riesce a mettere in pratica ciò che ha appreso. Al fine di limitare queste mancanze, nasce Programmiamo con Inforge.

In questa rubrica potrai scrivere codice per la risoluzione di alcuni problemi legati alla programmazione, mettendo in pratica quanto stai apprendendo dalla teoria oppure mostrando le tue abilità e competenze nel campo dell’informatica.


Partiamo dalle basi del C

In questa guida puoi trovare i testi per studiare e approfondire il C: I migliori libri per imparare e approfondire il C
In questa discussione puoi trovare le risposte alle domande più frequenti su come scrivere codice in C: Frequently asked questions: da dove si parte?


Esercitazione 03 in C | Livello intermedio | [Programmazione concorrente]

La concorrenza è una caratteristica dei sistemi di elaborazione nei quali può verificarsi che un insieme di processi o sotto-processi sia in esecuzione nello stesso istante (un'importante classe di sistemi informatici nei quali gli aspetti di concorrenza sono fondamentali è quella dei sistemi operativi)
L'esercitazione si compone di 5 esercizi nei quali ti sarà richiesto di compiere delle operazioni base su thread e processi mediante l'utilizzo di funzioni come pid() e fork()


*** Hidden text: cannot be quoted. ***


Soluzioni

Per rendere l'esercitazione più interessante, non verrà pubblicata alcuna soluzione! Spetterà a te scrivere la tua versione del codice e pubblicarla in questo thread così che possa essere valutata dai moderatori e dalla community; il modo migliore per imparare!

Conclusioni

Pubblica la soluzione ottimale per risolvere gli esercizi e ricorda che puoi confrontarti con il resto della community in questo thread, chiedere aiuto o aiutare gli altri ;)
Grazie per il vostro lavoro!
Messaggio unito automaticamente:

Grazie!