Search code examples
clinuxwaitshared-memorycritical-section

C programm with wait(NULL) doesnt end like it should


I have written this code which is supposed to make N producers (P) and a consumer (C). Those two exchange K messages which are in two separate shared memory segments (sms). P's send to C a line and their pid. C sends back this line capitalized with the pid of the P that sent it. When K messages have been sent C must calculate and print how many times P's have read their own message capitalized. I put a wait(NULL) in the end so that C waits for all P's to put their personal pid_match in a buffer of a 3rd sms so it can read the right values after. Instead when i execute the code it only reads the pid_match from the 1st P and then terminates. Why does that happen. I post the code below. If any examples of execution are usefull i can provide them.

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>   
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #include <string.h>
    #include <ctype.h>
    #include <time.h>
    #include "myheader.h"

    int main (int argc , char* argv[]){

    if(argc<3) {
      printf("Programm needs more arguments (K and N) \n");
    return(-1);
}
else
{
    const int SHMSIZE = sizeof(struct message);             // Shared Memory size = the size of a message
    int K, N, k, n, child_pid, shmid_in, shmid_out, shmid_pid, full_in, empty_in, full_out, empty_out, empty_pid, full_pid, pid_match=0,status,G;
    key_t shmkey_in, shmkey_out, semkey0_in, semkey1_in, semkey0_out, semkey1_out;
    struct message *shm_in, *shm_out;
    int *shm_pid;
    //struct sembuf oparray[1]={0,1,0};


    K=atoi(argv[1]);
    N=atoi(argv[2]);
    const int shm_pidsize = N*sizeof(int);

    if(K==0 || N==0) return 0; //if no producers exist the programm should exit
    printf("%d %d \n", K, N );


    /* --- Keys Initialization --- */
    shmkey_in = ftok("/OS1.c", 1);
    shmkey_out = ftok("/OS1.c", 2);

    semkey0_in = ftok("/OS1.c", 3);     // full_in semkey
    semkey1_in = ftok("/OS1.c", 4);     // empty_in semkey          Tou P oi 2 gia to sms in (apo P se C dld)

    semkey0_out = ftok("/OS1.c", 5);        // full_out semkey      
    semkey1_out = ftok("OS1.c", 6);     // empty_out semkey         Tou P oi 2 gia to sms out (apo C se P dld)


    /* --- Shared memory creation --- */
    shmid_in = shmget(IPC_PRIVATE,SHMSIZE, IPC_CREAT | 0666);
    shmid_out = shmget(IPC_PRIVATE,SHMSIZE, IPC_CREAT | 0666);
    shmid_pid = shmget(IPC_PRIVATE,shm_pidsize,IPC_CREAT | 0666);       // shm_pid creation

    shm_in = (struct message*)shmat(shmid_in,NULL,0);
    shm_out = (struct message*)shmat(shmid_out,NULL,0);
    shm_pid = (int*)shmat(shmid_pid,NULL,0);        // shm_pid attach


    /* --- Semaphore creation --- */
    full_in = semget(IPC_PRIVATE,1,IPC_CREAT | 0666);
    empty_in = semget(IPC_PRIVATE,1,IPC_CREAT | 0666);

    full_out = semget(IPC_PRIVATE,1,IPC_CREAT | 0666);
    empty_out = semget(IPC_PRIVATE,1,IPC_CREAT | 0666);

    full_pid = semget(IPC_PRIVATE,1,IPC_CREAT | 0666);
    empty_pid = semget(IPC_PRIVATE,1,IPC_CREAT | 0666);


    /* --- Semaphore Initialization --- */
    union semum init0,init1;

    init0.val=0;
    init1.val=1;

    semctl(full_in,0,SETVAL,init0);     // full_in = 0
    semctl(empty_in,0,SETVAL,init1);    // empty_in = 1


    semctl(full_out,0,SETVAL,init0);    // full_out = 0
    semctl(empty_out,0,SETVAL,init1);   // emty_out = 1


    semctl(full_pid,0,SETVAL,init0);        // pid_full = 0
    semctl(empty_pid,0,SETVAL,init1);       // pid_empty = 1


    /* --- Semaphore oparations buffers --- */
    struct sembuf full_in_up = {0,1,0};
    struct sembuf full_in_down = {0,-1,0};
    struct sembuf empty_in_up = {0,1,0};                // Operations of P to semaphores 0,1,2
    struct sembuf empty_in_down = {0,-1,0};

    struct sembuf full_out_up = {0,1,0};
    struct sembuf full_out_down = {0,-1,0};
    struct sembuf empty_out_up = {0,1,0};               // Operations of C to semaphores 0,1,2
    struct sembuf empty_out_down = {0,-1,0};

    struct sembuf full_pid_up = {0,1,0};
    struct sembuf full_pid_down = {0,-1,0};
    struct sembuf empty_pid_up = {0,1,0};
    struct sembuf empty_pid_down = {0,-1,0};

    for(n=0; n<N; n++)
    {


        child_pid = fork();
        //printf("child_pid = fork();\n ");
        if (child_pid == 0)
        {
            printf(" --- this is %d th child with pid: %d---\n \n", n, getpid());
            int pid_match = 0;      // Initialize pid_match
            while(1){
                        //printf("int pid_match = 0;        // Initialize pid_match\n while(1){\n");
                        // printf("%d \n",semctl(empty_in,0,GETVAL));
                        // sleep(1);
                        semop(empty_in, &empty_in_down,1); // down(empty_in)
                        // printf("%d \n",semctl(empty_in,0,GETVAL));
                        //printf(" down(empty_in)\n");                      
                        struct message msg;
                        msg.pid = getpid();

                        char buf[max_line_length];
                        FILE *ptr_file;     
                        ptr_file =fopen("input.txt","r");
                        if (!ptr_file) perror("File failed to open");
                        long curtime = time(NULL);
                        srand((unsigned int) curtime);      
                        sleep(1);                       // produce & send
                        int i=1, j=0, luckyline = rand() % 5 + 1;
                        //printf("%d\n", luckyline);
                        while (fgets(buf, 1000, ptr_file)!=NULL && i<5)
                        {

                            if (i == luckyline)
                            {
                                //printf("%s \n",buf);
                                strcpy(msg.line,buf);   // complete the message

                                strcpy(shm_in->line,msg.line);  // send message to sms
                                shm_in->pid = getpid();
                                //printf("pid = %d\n",shm_in->pid );
                                break;
                            }
                            i++;
                        }



                        fclose(ptr_file);

                        // strcpy(shm_in->line, "message");
                        // printf("message copy\n");
                        // shm_in->pid = child_pid;


                        semop(full_in,&full_in_up,1);  // up full
                        //printf("shared memory in full \n");

                         // read from C and kill if K messages have been sent
                        semop(full_out,&full_out_down,1);   // down full

                        //if (strcmp(shm_out->line,"kill")!=0) printf("%s\n", shm_out->line);


                        if (strcmp(shm_out->line,"kill") == 0)      
                        {
                            semop(empty_pid,&empty_pid_down,1);

                            shm_pid[j]=pid_match;
                            j++;

                            semop(full_pid,&full_pid_up,1);
                            printf("%d pid_match = %d\n",getpid(),pid_match );
                            printf("kill\n");
                            exit(1);
                        }

                        if (shm_out->pid == getpid())
                        {
                            //strcpy(shm_out->line,"\0");                                               shm_out->pid = 0;
                            printf("Pid's match\n");
                            pid_match++;                    
                        }


                        semop(empty_out,&empty_out_up,1);   // empty up

                    }
                    //sleep(20);

        }else if(child_pid < 0){
            perror("fork failed\n");
        }else
        {
            // break;
        }
    }

    for (k=0; k<K; k++)
    {
        int j=0;
        struct message m_out;
        //printf("Consumer running\n");
        semop(full_in,&full_in_down,1); //down full _in
        //sleep(1);
        //printf("Full got 'downed'\n");
        m_out.pid = shm_in->pid;
        while (shm_in->line[j] != '\0')
            {
                m_out.line[j] = toupper(shm_in->line[j]);           // write in m_out->line the content of shm_in->line capitalized
                j++;
            }
        /*if (k == K)
        {
            printf("kill\n");
            strcpy(shm_out->line, "kill");

        }*/

        semop(empty_in,&empty_in_up,1); //up empty_in



        semop(empty_out,&empty_out_down,1); // down empty_out

        //printf("shm_in->line = %s \n", shm_in->line );
        // m_out->line = shm_in->line;                              // capitalize & send
        //strcpy(shm_out->line,m_out.line);
        //shm_out->pid = m_out.pid;                 

        printf("shm_in->line = %s \n", shm_in->line );
        strcpy(shm_out->line,m_out.line);
        printf("shm_out->line = %s\n", shm_out->line);
        shm_out->pid = m_out.pid;


        semop(full_out,&full_out_up,1); //up full
    }

        if (k == K)
        {
            printf("C kill\n");
            semop(empty_out,&empty_out_down,1);
            strcpy(shm_out->line, "kill");
            semop(full_out,&full_out_up,1);

        }

    wait(NULL);
    //sleep(2);
    //printf("pid_match = %s\n",pid_match);
    for(G=0; G<N; G++){
        //sleep(2);
        pid_match += shm_pid[G];
        //printf("(pid_match = %s\n",pid_match);
        if(G == N-1)
        printf("Completed execution, exit %d\n",pid_match );
    }

    /* --- TERM ---*/
semctl(full_out,0,IPC_RMID,0);
semctl(full_in,0,IPC_RMID,0);
semctl(empty_out,IPC_RMID,0);
semctl(empty_in,0,IPC_RMID,0);
semctl(full_pid,0,IPC_RMID,0);
semctl(empty_pid,0,IPC_RMID,0);

shmdt(shm_pid);
shmdt(shm_in);
shmdt(shm_out);
}


return 0;

}


Solution

  • The wait function with a NULL argument only waits for one child process to exit. Then it stops waiting.

    You need to wait for all processes to exit.

    You can do that by saving all child-process pids, and then wait in a loop until they have all exited (checking using the return value of wait).