4
votes

I have an assignment to write a program in c language that will print to the shell the numbers 1 - 100. I must use 5 processes. The first one will print 1, 6, 11, 16... the second 2, 7, 12, 17... and so on. I need to create 5 semaphores that will synchronize those processes. The five semaphores need to be initialized with 0, 1, 2, 3, 4.

Does that mean I need to use semctl?

Also, it is said that the process that prints 1 must be initialized with 4, the process that prints 2 - initialized with 3 and so on.

How do I perform this action?

Finally, it is said that before printing a number, I need to perform wait 4 times to reduce the semaphore value by 4, and after printing the number I need to use signal to increase the other semaphore values by 1.

I have tried so many ways to do so, but can't solve it. I don't understand the timing between those processes- how do I make each process use a certain semaphore? And how do I "go back" to that process later, and without creating child processes inside the child processes I already have?

This is the most that I could achieve:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

void increaseallbutI(int i);
void cleanup();
int semid;
struct sembuf sops[1];

union semun
{
    int val;
    struct semid_ds * buff;
    unsigned short *array;
    struct seminfo *_buf;
};
union semun semarg;

void main()
{
    int i, j, k, status, num = 1;
    pid_t pid[5];

    semid=semget(IPC_PRIVATE, 5, 0600);

    for(i = 1; i < 17; i++)
    {
        signal(i, &cleanup);
    }

    for(i = 0; i < 5; i++)
    {
        semarg.val = 4 - i;
        semctl(semid, i, SETVAL, semarg);
    }

    sops->sem_num = 0;
    sops->sem_flg = 0;

    for(i = 0; i < 5; i++)
    {
        if(fork()==0)
        {
            for(j = i + 1; j < 101; j += 5)
            {
                wait(&status);
                wait(&status);
                wait(&status);
                wait(&status);
                printf("%d\n", j);
                fflush(stdout);

                signal(i, &increaseallbutI);
            }
        }
    }
}

void cleanup()
{
    semctl ( semid , 0 , IPC_RMID , semarg );
    exit(1);
}

void increaseallbutI(int i)
{
    int k;
    for(k = 0; k < 5; k++)
    {
        if(k != i)
        {
            sops->sem_op = 1;
            sops->sem_num = k;
            semop ( semid , sops , 1 );
        }
    }
    exit(1);
}
1
Your program won't work as it is since you're using the wait () function whose behavior is stopping the parent process until a child process returns. This means every process (parent and children) will wait for an exit which never arrives. What you actually want to use is a sem_wait function instead, which reduces the semaphore count by 1 and so you require 4 of them. Similarly, you need a sem_signal of some kind in order to increase the value of the semaphore. Did they tell you to implement your own semaphores, or are you allowed to use libraries? - ThCP
First, thank you so much for answering. Second, I think that I am allowed to use libraries. - eevee25
So, instead of those waits, I can call sem_wait? What should I pass as an argument? Do I need to create a sem_t sem and call sem_init(&sem, 0, 0)? - eevee25
You must use sem_wait. If you're using posix semaphores then you should check on the documentation the correct syntax, then you should initialize 5 different semaphores and initialize them correctly (which means using sem_init with the correct values for the semaphore e.g. 4 for sem 1 and so on). - ThCP

1 Answers

0
votes

The structure of your program is basically correct.

So, instead of those waits, I can call sem_wait? What should I pass as an argument? Do I need to create a sem_t sem and call sem_init(&sem, 0, 0)?

No, you and ThCP confused System V and POSIX semaphores. Since you are using System V semaphores (indeed better suited for your task), the function to be used for waiting is semop.

after printing the number I need to use signal to increase the other semaphore values by 1.

By signal, certainly not the function signal is meant, but the increasing of the semaphore values which you correctly do in the function increaseallbutI() is called signaling.

Thus, the main loop and the end of the program could become:

    …
    for (i = 0; i < 5; i++)
    {
        if (fork() == 0)
        {
            struct sembuf sop = { i, -4, };
            for (j = i + 1; j < 101; j += 5)
            {
                semop(semid, &sop, 1);
                printf("%d\n", j);
                increaseallbutI(i);
            }
            exit(0);    // child is done
        }
    }
    do ; while (wait(&status) > 0); // wait till all children are finished
    cleanup();
}

Don't forget to remove the exit(1) call in function increaseallbutI()!