'Print the numbers 1 to 100 using 5 semaphores and processes

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);
}


Solution 1:[1]

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()!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Armali