Hi everyone!
I have a task that needs to be made in C in Linux. I use Kubuntu.
This is the task:
Process (coordinator) creates 5 working process (pool of processes). The working processes are waiting to be awakened by the coordinator, perform a job and wait again. The coordinator transmits tag (integer) to the first process and it wakes it up. The awakened first process adds 1 to the tag and transmit it to the next process, as it signals the coordinator. The coordinator awakens the next process, which performs same actions etc. The tag should pass through each process 10 times and then the coordinator should visualize its contents. Use signals for the signalization of the processes, and for the tag (marker) use channels.
Solve the problem also with threads by selecting the most appropriate way of communication.

Any ideas? I'm absolutely clueless about this.
Thanks in advance!

What is meant by "channels"? I remember shared memory, pipe, message queue, domain sockets as IPC mechanisms on Posix, but not channels.

Yes, they are pipes. Sorry, sometimes we refer to them as channels. My bad:-)

Yes, they are pipes. Sorry, sometimes we refer to them as channels. My bad:-)

All this doesn't make sense. First off, pipes don't need external synchronization because the reader process will be awaken by the kernel when there's data in the pipe. Also, pipe is useful in 1-to-1 schemes, not 1-to-n schemes. Secondly, in a 1-to-n scheme like this, a worker do not pass data to the next worker because it is not (should not be) aware of other workers, hence that's why there's an overseer(coordinator) process.
This more looks like a case of shared memory, since it requires explicit synchronization between processes.

Well the task was created by the teachers. Guess they don't know how it should work either:-)

Well the task was created by the teachers. Guess they don't know how it should work either:-)

Yes, I totally get what you mean. Assigments like this make me remember the awful experiences and frustration I had in university years ago. It's sad to see similar ignorance(and hubris) in faculty after all that time.
Note that, it also wants you to solve this using threads, which is quite a different beast in Posix systems.
When is this due? Can you at least get a diagram showing between which processes the teacher expects pipes to be established?

Well the only thing that they've told me is that for new processes I should use fork() (like I didn't know that) and for the synchronization (the part where the processes are 'awakened') I should use pipes. And that was the whole explanation.
So I imagine it something like this:
One main process (which will be the coordinator) with fork() will create 5 child processes. Then the main process will place a tag (marker) i.e will awaken the first child process. The other four child processes will wait until it is their turn to accept the tag. And after 10 times of transmitting the tag around the child processes, the main process will print the contents of the marker.
This is how I think the assignment should be.
The worst part is that we still haven't learned about shared memory or pipes (we learned only about signals) and they expect this to be done before Christmas (20th December or something).
I'm so sorry that I can't explain this better, but I'm also very clueless how to make this thing to work.
Oh and if we manage to do this first part, the threads can be skipped.
Thanks:-)

OK, I suggest using one pipe with one producer(coordinator) and 5 consumers(workers). This makes the need for an explicit signalling mechanism so that the workers do not read from the pipe at the same time (and they won't block on read() from pipe, but sleep() in a loop). It's actually an ugly shared memory using pipe. How does it sound?

Yeah I sounds great! It would be even greater if I knew how to do it:-). But no it is great, it is a nice idea.
It is like having one pipe for every child process (from the controller to the child processes), but not child between child. That way the signalization may be solved. I don't know I'm just guessing.

Edited 5 Years Ago by didi00: n/a

Argh.. pipes on Linux are not duplex. So we'll need 2 pipes.
Anyway, I'll try to come up with something this weekend latest (I've not used pipe in multiple consumer context before, it'll be interesting :-) )

Oh... I'm sorry:-(. Sorry for my ignorance. I just don't know much about pipes. But thank you for your help:-)
Cheers!

I googled a little bit and I think that something like a socketpair() might work. I don't know, I've never used it, but maybe its some idea. I don't know...

I googled a little bit and I think that something like a socketpair() might work. I don't know, I've never used it, but maybe its some idea. I don't know...

That's about domain sockets, not pipes. I asked you first about these and you said pipe.

Alright, here you go:

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

#define nWORKERS 5
#define nTOURS	10
#define FIRST_TAG 60


void sig_handle(int signum) { return; }

int main(int argc, char *argv[])
{
	int i, j, tag, pipefd[2], end_trigger=-1;
	pid_t worker[nWORKERS], co_pid;
	const struct sigaction siga = { sig_handle, 0, 0, 0, 0 };
	sigset_t sset, prev_sset;
	
	sigemptyset(&sset);
	sigaddset(&sset, SIGUSR1);
	sigprocmask(SIG_BLOCK, &sset, &prev_sset);

	if (sigaction(SIGUSR1, &siga, NULL) == -1) {
		perror("sigaction()");
		exit(EXIT_FAILURE);
	}
	if (pipe(pipefd) == -1) {
		perror("pipe()");
		exit(EXIT_FAILURE);
	}
	
	for (i=0; i < nWORKERS; i++)
	
		if ((worker[i] = fork()) == -1) {
			perror("fork()");
			exit(EXIT_FAILURE);
		}
		
		else if (worker[i] == 0)  { /* child worker */
		
			co_pid = getppid();
			
			while (1) {	
				kill(co_pid, SIGUSR1);
				sigsuspend(&prev_sset);
				if (read(pipefd[0], &tag, sizeof(int)) == -1) {
					perror("read() in worker");
					exit(EXIT_FAILURE);
				}
				if (tag == end_trigger) {
					printf("---worker received end trigger\n");
					close(pipefd[0]);
					close(pipefd[1]);
					exit(EXIT_SUCCESS);
				}

				tag++;
				printf("---worker producing tag:%d\n", tag);
				if (write(pipefd[1], &tag, sizeof(int)) == -1) {
					perror("write() in worker");
					exit(EXIT_FAILURE);
				}
			}			
		}		
		else   /* parent coord. */
			sigsuspend(&prev_sset);			

	
	for (tag=FIRST_TAG, i=0; i < nTOURS; i++) {
	
		printf("Tour: %d\n", i);
	
		for (j=0; j < nWORKERS; j++) {
		
			printf("Sending tag:%d to worker %d\n", tag, j);
		
			if (write(pipefd[1], &tag, sizeof(int)) == -1) {
				perror("write in coord.");
				exit(EXIT_FAILURE);
			}
			kill(worker[j], SIGUSR1);
			
			sigsuspend(&prev_sset);
			if (read(pipefd[0], &tag, sizeof(int)) == -1) {
				perror("read in coord.");
				exit(EXIT_FAILURE);
			}
			
			printf("Received tag:%d from worker %d\n", tag, j);			
		}
	}
	
	for (i=0; i < nWORKERS; i++) {
		if (write(pipefd[1], &end_trigger, sizeof(int)) == -1) {
			perror("write() end trigger");
			exit(EXIT_FAILURE);
		}
		kill(worker[i], SIGUSR1);
		waitpid(worker[i], NULL, 0);
	}

	close(pipefd[0]);
	close(pipefd[1]);
	return(EXIT_SUCCESS);
}

I used only one pipe. Synchronization is via signals, but I had to use sigsuspend() instead of pause() to overcome the asynch nature of signals. I also used a value to convey termination from coordinator to workers via a variable named end_trigger, which defaults to -1. I set the initial tag to 60, but you can change that if you want (just make sure it's never -1). You can also change the number of workers and tours, see the #define's at the top.
Overall this is probably not trivial to you, but study and try to understand for a while. I suppose you're a junior or senior in computer science and are (or will have to be) familiar with asynch nature of signals and process scheduling.

Comments
Amazing! THANK YOU!!!

Wow this is absolutely AMAZING! THANK YOU SO MUCH!!! I mean, you literally are THE BEST!!!
Thank you, I will start to study the code line by line and I will see what is going on with this code!
Again, THANK YOU!!!:-D

Let me state that this is actually not a good example of multiprocessing. Why? Because only 1 worker is active at a time, the others are simply on hold. The same effect/performance could be achieved using just one process as well, hence it's a pointless way of using multiple workers. But this is a homework, so it's OK to be that way.

I'm sorry that I'm here again but I just made my virtual box to work.
OK so it compiled great and runs... well I don't know how it runs.
It just does nothing. You can write something like normal text, and it doesn't stop.
Am I doing something wrong?
What output should I expect from it?
Sorry for the bothering, its just I don't know what to do.

Anyone can help me?
I need to know if there's something wrong with the code or the virtual box.
Thank you!

OK so it compiled great and runs... well I don't know how it runs.
It just does nothing. You can write something like normal text, and it doesn't stop.

Wow, dude... I spent like 4 hours and gave you some nontrivial code that works flawlessly, even annotated with explanations and comments, yet you managed to disparage it. Just.. WOW!!
People like you are the solid proof that noone can build a positive reputation on the Internet, and people like me are just fools who hope maybe this time it is different.. but no, it's never different: No good deed goes unpunished, and this is my punishment for giving so much without taking anything.
So, from now on nothing comes free from me. My opening rate is 200 Euros, to be directly deposited to my Paypal account. And for something nontrivial like this, I want min. 500 Euros. Otherwise, I'll just have fun fooling around and typing anything I want to anyone I want, that's the way of Internet, right?

No, no it is OK. I'm sorry. The problem was in the Virtual box, but now it is done. I'm sorry if I disturbed you, I didn't mean to harm your reputation. I'm SO sorry.
I guess I should've post that everything is OK.
Please, forgive me if I made you feel bad. The code works great!
I feel very bad. I'm so, SO sorry :-(

This question has already been answered. Start a new discussion instead.