My program has to increment a counter strictly alternatively using 2 threads and synchronizing them using a pipe file. I know it doesn't really make sense but it's a university task. The problem works if I run it with CodeBlocks for instance but it doesn't print anything when I execute the program from linux terminal and I can't figure out why. Any idea?
Here is my code:
#include <stdlib.h>
#include <pthread.h>
#include <wait.h>
#include <unistd.h>
#include <string.h>
int contor;
int fd[2];
void* thread_function(void* arg) {
int* th = (int*)arg;
char x = 'x';
while(1)
{
if (*th == 0 && contor % 2 == 0 && contor < 100) {
close(fd[0]);
write(fd[1], &x, 1);
contor++;
printf("Counter: %d incremented by thread: %ld\n", contor, pthread_self());
sleep(0);
if (contor >= 100)
{
pthread_exit(NULL);
}
} else if (*th == 1 && contor % 2 == 1 && contor < 100){
close(fd[1]);
read(fd[0], &x, 1);
contor++;
printf("Counter: %d incremented by thread: %ld\n", contor, pthread_self());
if (contor >= 100)
{
pthread_exit(NULL);
}
}
if (contor >= 100)
{
pthread_exit(NULL);
}
}
}
void main(int argc, char** argv) {
int tr1 = 0;
int tr2 = 0;
pthread_t t1, t2;
int th0 = 0;
pipe(fd);
tr1 = pthread_create(&t1, NULL, &thread_function, (void*)&th0);
if (tr1) {
printf("Error creating thread #1!");
}
int th1 = 1;
tr2 = pthread_create(&t2, NULL, &thread_function, (void*)&th1);
if (tr2) {
printf("Error creating thread #2!");
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
}
I compile the file using: gcc -o ex.exe ex.c -lpthread
I execute the executable using: ./ex.exe
File descriptors are shared by all the threads of a process. One of your threads is closing one end of the pipe (fd[0]) and writing the other end of the pipe (fd[1]). Your other thread is closing the other end of the pipe (fd[1]) and reading the other end of the pipe (fd[0]). Also, they are being closed multiple times in a while loop.
Getting rid of the close(fd[0]) and close(fd[1]) calls in thread_function will help a bit. There may be other problems in thread_function because the program stopped producing output after the counter reached the value 3 when I tried it.
Hint: Use two pipes.
Related
Referring to following code example, I want the main thread to supply the number num that the child thread is expecting using scanf.
I tried this way to write the wordcount (9) to stdin which is to be read by child thread, but it is not working.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void* child_thread_func(void* terminalflag)
{
int num=0;
printf("Trying to read num from stdin\n");
scanf("%d",&num);
/*expecting 9 to be printed here*/
printf("Entered number is %d\n", num);
}
int main () {
pthread_t tid;
if (pthread_create(&tid, NULL, &child_thread_func, NULL) != 0) {
printf("Failed to initialize thread\n");
exit(1);
}
sleep(2);
char buffer[50];
FILE *wfp = popen("wc -c", "w");
if (wfp != NULL) {
sprintf(buffer, "dummyword");
int save_stdin = dup(fileno(stdin));
dup2(fileno(wfp), fileno(stdin));
fwrite(buffer, sizeof(char), strlen(buffer), wfp);
dup2(save_stdin, fileno(stdin));
pclose(wfp);
}
pthread_join(tid, NULL);
}
Can someone suggest a correct way or any other alternative way to do this?
Thanks.
I don't think there is any good way for a process to write text to its own stdin; stdin is meant to be a way for the parent process (or the user, if the parent process is a Terminal window) to send data to your process, not for your process to send data to itself.
However, you could achieve a similar result by having your child thread use select() or similar to read input from both stdin and from the output end of a pipe; then your parent process can send data to the child process by writing to the input end of that same pipe.
Below is a modified version of your program demonstrating the technique. Note that the child thread will print out any text that you type into stdin; and also the main thread will send a line of text to the child thread once every 5 seconds, and the child thread will also print out that text. After the main thread has sent 5 messages to the child thread, the main thread will close its end of the pipe, causing the child thread to exit and then the process can exit cleanly as well.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
static int pipeReadFD = -1;
static int ReadTextFrom(const char * descriptionOfSender, int fd)
{
char buf[256];
const int numBytesRead = read(fd, buf, sizeof(buf)-1); // -1 so we always have room to place NUL terminator byte
if (numBytesRead > 0)
{
buf[numBytesRead] = '\0'; // make sure the string is NUL-terminated
printf("ReadTextFrom(): Read %i bytes from [%s]: [%s]\n", numBytesRead, descriptionOfSender, buf);
}
return numBytesRead;
}
void* init_on_sys_ready(void* terminalflag)
{
int num=0;
printf("Child thread: trying to read text from stdin\n");
while(1)
{
const int stdinFD = fileno(stdin);
const int maxFD = (pipeReadFD > stdinFD) ? pipeReadFD : stdinFD;
fd_set readFDSet;
FD_ZERO(&readFDSet);
FD_SET(stdinFD, &readFDSet);
FD_SET(pipeReadFD, &readFDSet);
const int selRet = select(maxFD+1, &readFDSet, NULL, NULL, NULL);
if (selRet >= 0)
{
if ((FD_ISSET(stdinFD, &readFDSet))&&(ReadTextFrom("stdin", stdinFD) <= 0)) break;
if ((FD_ISSET(pipeReadFD, &readFDSet))&&(ReadTextFrom("pipe", pipeReadFD) <= 0)) break;
}
else
{
perror("select");
break;
}
}
printf("Child thread exiting!\n");
return NULL;
}
int main(int argc, char ** argv)
{
int pipeFDs[2];
if (pipe(pipeFDs) < 0)
{
perror("pipe");
return -1;
}
pipeReadFD = pipeFDs[0];
int pipeWriteFD = pipeFDs[1];
pthread_t tid;
if (pthread_create(&tid, NULL, &init_on_sys_ready, NULL) != 0) {
printf("Failed to initialize CLI\n");
exit(1);
}
int count = 0;
for (int count=0; count < 5; count++)
{
char buf[512];
snprintf(buf, sizeof(buf), "Hello #%i from main thread", ++count);
const size_t slen = strlen(buf);
if (write(pipeWriteFD, buf, slen) == slen)
{
printf("main() sent [%s] to the child thread via the pipe.\n", buf);
}
else
{
perror("write");
break;
}
sleep(5);
}
close(pipeWriteFD); // this will cause the child thread to exit ASAP
pthread_join(tid, NULL);
return 0;
}
popen's man states:
[...] the command's standard output is the same as that of the process that called popen()
So you just need a way to redirect stdout to stdin.
Which is exactly what pipe is for. It links an output fd with an input fd.
As pipe creates new fds, we need to use dup2 to replace stdin and stdout, as you've already did in your example code. Threads share the same memory, so you don't have to worry about any child/parent differences in fds.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void* child_thread_func(void* terminalflag)
{
int num=0;
printf("Trying to read num from stdin\n");
scanf("%d",&num);
/*expecting 9 to be printed here*/
printf("Entered number is %d\n", num);
}
int main () {
setbuf(stdin, NULL);
pthread_t tid;
if (pthread_create(&tid, NULL, &child_thread_func, NULL) != 0) {
printf("Failed to initialize thread\n");
exit(1);
}
int save_stdin = dup(STDIN_FILENO);
int save_stdout = dup(STDOUT_FILENO);
int tube[2];
pipe(tube);
dup2(tube[0], STDIN_FILENO);
dup2(tube[1], STDOUT_FILENO);
char buffer[50] = {0};
FILE *wfp = popen("wc -c", "w");
if (wfp != NULL) {
sprintf(buffer, "dummyword");
fwrite(buffer, sizeof(char), strlen(buffer), wfp);
pclose(wfp);
}
dup2(save_stdin, STDIN_FILENO);
dup2(save_stdout, STDOUT_FILENO);
pthread_join(tid, NULL);
}
I've been working on the following code for quite some time, but can't really figure it out.
The task is to read a terminal command and to run it every x seconds; if the command hasn't finished within the waiting time, we want to kill the process and afterwards run the command again.
Any help would be really appreciated.
I'm pretty sure I'm not using waitpid() correctly; how would I go about using waitpid to achieve the goal?
Additionally, how would I go about detecting an error within a child process? The plan is to kill the parent process if an error occurred in a child process.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
/*
*
*/
int main(int argc, char** argv) {
int waitingTime;
if (argc < 3) {
printf("Invalid number of arguments provided. Please specify a command and exactly one parameter.");
return (EXIT_FAILURE);
}
// -n parameter specified? If so, set the waiting time.
if (argc == 5 && strcmp(argv[3], "-n") == 0) {
waitingTime = atoi(argv[4]);
} else {
waitingTime = 5; // Default waiting time.
}
char* cmd = (char*)malloc(sizeof(argv[1]));
cmd = argv[1];
char* param = (char*)malloc(sizeof(argv[2]));
param = argv[2];
// Print the read command and its param
printf("Command: %s, Parameter: %s, Interval: %d\n\n", cmd, param, waitingTime);
pid_t pid;
for (;;) {
// Declared here for scope
int secsWaited;
secsWaited = 0;
pid = fork();
if (pid == 0) {
pid = getpid();
printf("==============\n");
execlp(cmd, cmd, param, "/", (char *)NULL);
printf("Excec failed; killing the proccess.");
kill(pid, SIGKILL);
} else if (pid > 0) {
int status, code;
for (;;) {
code = waitpid(pid, &status, WNOHANG);
if (code == 0 && secsWaited >= waitingTime) {
kill(pid, SIGKILL);
printf("Child stopped");
break;
} else if (code == 0 && secsWaited < waitingTime) {
secsWaited++;
sleep(1);
} else {
break;
}
}
/*if (!WIFEXITED(status)) {
printf("Time exceeding, stopping child.");
// Get parent process id and kill it.
kill(getpid(), SIGKILL);
}*/
// Sleep for the specified time
sleep(waitingTime - secsWaited);
} else {
return (EXIT_FAILURE);
}
}
free(cmd);
free(param);
return (EXIT_SUCCESS);
}
Your logic was a bit too complicated (e.g. too many different sleep calls and if/else ladder logic).
Also, no need to malloc the argv strings--they can be used directly.
I've simplified it and restructured a bit to get it to work [please pardon the gratuitous style cleanup]:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
/*
*
*/
int
main(int argc, char **argv)
{
int waitingTime;
if (argc < 3) {
printf("Invalid number of arguments provided. Please specify a command and exactly one parameter.");
return (EXIT_FAILURE);
}
// -n parameter specified? If so, set the waiting time.
if (argc == 5 && strcmp(argv[3], "-n") == 0) {
waitingTime = atoi(argv[4]);
}
else {
waitingTime = 5; // Default waiting time.
}
char *cmd = argv[1];
char *param = argv[2];
// Print the read command and its param
printf("Command: %s, Parameter: %s, Interval: %d\n\n",
cmd, param, waitingTime);
pid_t pid;
int code = -1;
int status;
int killflg = 1;
for (;;) {
// Declared here for scope
int secsWaited;
secsWaited = 0;
pid = fork();
// stop on fork failure
if (pid < 0) {
killflg = 1;
break;
}
// child process
if (pid == 0) {
pid = getpid();
printf("==============\n");
#if 0
execlp(cmd, cmd, param, "/", (char *) NULL);
#else
execlp(cmd, cmd, param, (char *) NULL);
#endif
printf("Excec failed; killing the proccess.");
// NOTE/BUG: this is the child so pid is zero, so killing it is wrong
#if 0
kill(pid, SIGKILL);
#else
exit(1);
#endif
}
killflg = 0;
for (;;) {
code = waitpid(pid, &status, WNOHANG);
if (code > 0)
break;
if (killflg)
continue;
secsWaited++;
sleep(1);
if (secsWaited >= waitingTime) {
printf("timeout\n");
kill(pid, SIGKILL);
killflg = 1;
}
}
if (! killflg)
break;
}
#if 0
free(cmd);
free(param);
#endif
if (killflg)
code = EXIT_FAILURE;
else
code = EXIT_SUCCESS;
return code;
}
UPDATE:
Right now, the program will stop after one iteration; if I remove the breakpoint at if (! killflg), it will work as expected. Am I missing something or is this just a misunderstanding?
You are correct--my bad. I had missed the following in your question:
The task is to read a terminal command and to run it every x seconds;
Change the break into sleep(waitingTime - secsWaited).
But, a more robust way to keep track of elapsed time may be via two calls to time(2):
After the killflg = 0, do: time_t todbeg = time(NULL); time_t todelap;. Then, you can get elapsed time [anywhere] with: todelap = time(NULL) - todbeg; [here, todelap is similar to secsWaited]. This may be better than incrementing secsWaited.
time only has seconds resolution. For more precision control, consider using clock_gettime [has nanosecond resolution].
Here's a function that I use a lot for elapsed time [in fractional seconds]:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <time.h>
double
tvgetf(void)
{
struct timespec ts;
double sec;
clock_gettime(CLOCK_REALTIME,&ts);
sec = ts.tv_nsec;
sec /= 1e9;
sec += ts.tv_sec;
return sec;
}
/*
*
*/
int
main(int argc, char **argv)
{
int waitingTime;
if (argc < 3) {
printf("Invalid number of arguments provided. Please specify a command and exactly one parameter.");
return (EXIT_FAILURE);
}
// -n parameter specified? If so, set the waiting time.
if (argc == 5 && strcmp(argv[3], "-n") == 0) {
waitingTime = atoi(argv[4]);
}
else {
waitingTime = 5; // Default waiting time.
}
char *cmd = argv[1];
char *param = argv[2];
// Print the read command and its param
printf("Command: %s, Parameter: %s, Interval: %d\n\n", cmd, param, waitingTime);
pid_t pid;
int code = -1;
int status;
int killflg = 1;
double todzero = tvgetf();
for (;;) {
// Declared here for scope
double todbeg = tvgetf();
double todelap;
pid = fork();
// stop on fork failure
if (pid < 0) {
killflg = 1;
break;
}
// child process
if (pid == 0) {
pid = getpid();
printf("============== (%.9f)\n",tvgetf() - todzero);
execlp(cmd, cmd, param, (char *) NULL);
printf("Excec failed; killing the proccess.");
exit(1);
}
killflg = 0;
for (;;) {
code = waitpid(pid, &status, WNOHANG);
if (code > 0)
break;
if (killflg)
continue;
usleep(1000);
todelap = tvgetf() - todbeg;
if (todelap >= waitingTime) {
printf("timeout\n");
kill(pid, SIGKILL);
killflg = 1;
}
}
// do _not_ wait -- we already timed out
if (killflg)
continue;
// get final elapsed time for this round and the amount of time
// remaining until the next interval
todelap = tvgetf() - todbeg;
useconds_t time_to_wait = ((double) waitingTime - todelap) * 1e6;
// wait until the next time period
if (time_to_wait > 0)
usleep(time_to_wait);
}
if (killflg)
code = EXIT_FAILURE;
else
code = EXIT_SUCCESS;
return code;
}
Side note: I used usleep here, but, although slightly more complex, it's considered better to use nanosleep
I have 2 processes running test.c. There is a signal handler in test.c which executes an execlp. In test.c, I have a static variable which needs to be only initialized once, and incremented each time before the execlp call. When either process reaches 99, they exit.
Unfortunately, right now, it's not getting incremented, my guess is because there are 2 processes that each have a copy of the static variable. Here is test.c:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static int i = 0;
static int foo(int j)
{
printf("In the foo...\n");
j++;
printf("%d\n", j);
return j;
}
void main(int argc, char *argv[])
{
int pid, pid2, k;
int *h = malloc(sizeof(int));
int g = 0;
h = &g;
static char s[15];
pid = fork();
if (pid > 0)
{
sleep(1);
}
if (pid == 0)
{
k = foo(*h);
sprintf(s, "%d", k);
if (k >= 99)
{
printf("k=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
pid2 = fork();
if (pid2 == 0)
{
k = foo(*h);
sprintf(s, "%d", k);
if (k >= 99)
{
printf("k=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
wait(pid2);
wait(pid);
}
Can anyone please explain why there is an infinite loop? Why isn't the static variable get incremented?
Thank you.
Use Interprocess communication concepts (pipe, fifo, shared memory) here, execlp function overwrites memory of current program with new program. So when ever you call execlp gets called your program get refreshed and starts from begining and static int i is always 0.
I recommend to use pipe Refer this.
You need to use memory projection (mmap function) if you want to use the concept of shared memory between process.
In your code, the variable 'h' is the shared variable between the three process.It should defined using mmap function and initialized in the main process and then incremented in the two child process.
The answers to your two questions are related: either of the two child process never exits (exit(0)) because the if(k>=99) is never statisfied. This is due to the non-shared variable h which doesn't get incremented.
I will rather use a while loop and a return type main function.
By the way, you don't need the 'g' varibale, you can initialize directly 'h'. And there is no need of declaring the function foo as static (static functions are only useful when you want them to visible only with the file where they are defined). The buffer 's' can be declared non static (it is only a buffer which contains the value of k)
Here is a modified version of your code, it compiles and works fine.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
int foo(int* j)
{
printf("In the foo...\n");
(*j)++;
printf("%d\n", *j);
return *j;
}
int main(void)
{
int pid, pid2, k;
char s[15];
int * h = (int*)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (h == MAP_FAILED) {
printf("map failed\n");
return -1;
}
*h = 0;
pid = fork();
if (pid < 0) {
printf("fork failed pid\n");
return -1;
}
if (pid > 0) {
sleep(1);
}
else {
while(1) {
k = foo(h);
sprintf(s, "%d", k);
if (k>=99) {
printf("k>=99\n");
printf("%s\n", s);
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
}
pid2 = fork();
if (pid2 < 0) {
printf("fork failed pid2\n");
}
if (pid2 > 0) {
sleep(1);
}
else {
while(1) {
k = foo(h);
sprintf(s, "%d", k);
if (k>=99) {
printf("k>=99\n");
exit(0);
}
execlp("./a.out", "forktest", s, NULL);
}
}
wait(pid);
wait(pid2);
return 0;
}
Here is the output (only the last strings) click on the link:
output
I have the following assignment to do :
Ping-pong. Two processes will play the ping-pong game.
The first process will generate a random number between 5000 and 15000 that will be send to the other process.
This process will subtract a random value (between 50 and 1000) and will send the number back,
The chat between the processes will be implemented using pipe channels.
The game ends when the value is below zero.
Each process will print the received value.
So i wrote the following code :
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int p[2];
int a, n;
pipe(p);
int pid = fork();
if (pid == 0)
{
int r = 0;
srand(time(NULL));
while ( r < 50 || r > 1000)
{
r = rand();
}
if ((a=read(p[0], &n, sizeof(int)))==-1)
perror("Error read pipe:");
printf("Process 2 recived %d\n", a);
a = a - r;
close(p[0]); close(p[1]);
}
else if (pid > 0)
{
srand(time(NULL));
while ( n < 5000 || n > 15000) {
n = rand();
}
while (n > 0)
{
printf("Process 1 recived %d\n", n);
if (write(p[1], &n, sizeof(int))==-1)
perror("Error write pipe:");
wait(0);
}
}
return 0;
}
When it is executed it goes in a infinite loop which prints "Process 1 received 4" and i don't know why.
I created another pipe and now it prints correctly the first received value but from the second process it happens the same thing
Process 1 recived 9083
Process 2 recived 4
Process 1 recived 4
and infinite loop
I give you a corrected program with the explanation in comments:
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int p[2];
int p2[2];
int a, n;
pipe(p);
pipe(p2);
int pid = fork();
if (pid == 0)
{
close(p[1]); // not writing in p, so closing p[1] immediately
close(p2[0]); // not reading in p2, so closing p2[0] immediately
srand(time(NULL));
do {
if ((a = read(p[0], &n, sizeof(int)))==-1)
perror("Error read pipe:");
if (a == 0) // nothing read means all processes have closed p[1]
n = 0;
else
printf("Process 2 recived %d\n", n);
int r = 50 + rand() % 950; // Only need one random number, and need one different each time
n -= r;
if (n > 0)
{
if(write(p2[1], &n, sizeof(int))==-1)
perror("Error write pipe:");
}
} while (n > 0);
close(p[0]); close(p2[1]);
exit(0); // or return(0) - as pointed out by Stian
}
else if (pid > 0)
{
close(p[0]); // not reading in p, so closing p[0] immediately
close(p2[1]); // not writing in p2, so closing p2[1] immediately
srand(time(NULL) + pid); // Adding pid so that processes each use a different seed
n = rand() % 10000 + 5000; // Only need one random number
while (n > 0)
{
if (write(p[1], &n, sizeof(int))==-1)
perror("Error write pipe:");
// wait(0); Wrong use of wait()
if ((a = read(p2[0], &n, sizeof(int)))==-1)
perror("Error read pipe:");
if (a == 0) // nothing read means all processes have closed p2[1]
n = 0;
else
printf("Process 1 recived %d\n", n);
int r = 50 + rand() % 950;
n -= r;
}
close(p[1]); close(p2[0]);
}
wait(NULL); // Better use of wait(). Still not perfect, you need to check return value.
return 0;
}
You need two pipes. One for each direction
Suppose we have expression g=(a+b)*(c+d)-(e/f) with hard-coded arbitrary numbers for variables. I would like to calculate this expression using multiple child processes in order to better understand how fork() works.
My first attempt was to calculate (a + b) on child pid1, (c + d) on child pid2, (e / f) on child pid3, and then do summation & subtraction in the parent process.
Well, to my disappointment, (a + b) calculation done in the child process pid1 did not affect double expression1 variable in the parent process. I think the reason behind that - each fork() creates a separate memory space; as soon as a child process exits, all calculations done in that child process are gone.
What do you usually do in a situation like this? I thought maybe I could nest fork() child process within a child process to calculate (a + b) first; wait; then (c + d); wait; (e / f); wait; the first child calculates the entire expression; child return(0); parent terminates.
But I think there's an easier solution to this problem, am I right?
If you insist on using fork() , so here is my answer now using child process and shared memory
Note that exit() is used here the way it is expected by the system: to signalize if the child has exited normally or not.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
struct shared{
int a_b;
int c_d;
int e_f;
};
const int a=1,b=2,c=3,d=4,e=6,f=2;
const key_t key = 1234;
pid_t pab,pcd,pef;
void* shared_mem;
int main(){
//Parent process create the shared memory
int shmid = shmget(key,sizeof(struct shared), 0666|IPC_CREAT);
if(shmid == -1) exit(EXIT_FAILURE);
//Fork child
pab = fork();
if(pab == 0){
//Inside process ab
//attach to shared memory
shared_mem = shmat(shmid,(void*) 0,0);
if(shared_mem == (void*) -1) exit (EXIT_FAILURE);
struct shared* shared_data = (struct shared*) shared_mem;
shared_data->a_b = a +b;
//detach
if(shmdt(shared_mem) == -1) exit (EXIT_FAILURE);
exit(EXIT_SUCCESS);
}else {
pcd = fork();
if(pcd == 0){
//Inside process cd
//attach to shared memory
shared_mem = shmat(shmid,(void*) 0,0);
if(shared_mem == (void*) -1) exit (EXIT_FAILURE);
struct shared* shared_data = (struct shared*) shared_mem;
shared_data->c_d = c+d;
//detach
if(shmdt(shared_mem) == -1) exit (EXIT_FAILURE);
exit(EXIT_SUCCESS);
}else{
pef = fork();
if(pef == 0){
//Inside process ef
//attach to shared memory
shared_mem = shmat(shmid,(void*) 0,0);
if(shared_mem == (void*) -1) exit (EXIT_FAILURE);
struct shared* shared_data = (struct shared*) shared_mem;
shared_data->e_f = e/f;
//detach
if(shmdt(shared_mem) == -1) exit (EXIT_FAILURE);
exit(EXIT_SUCCESS);
}
}
}
//Wait child process termination
int status_ab,status_cd,status_ef;
waitpid(pab,&status_ab,0);
waitpid(pcd,&status_cd,0);
waitpid(pef,&status_ef,0);
//Check if all child exited normally
if(!WIFEXITED(status_ab) || !WIFEXITED(status_cd)||!WIFEXITED(status_ef)){
exit(EXIT_FAILURE);
}
//Parent attaches to memory
shared_mem = shmat(shmid,(void*) 0,0);
if(shared_mem == (void*) -1) exit (EXIT_FAILURE);
struct shared* shared_data = (struct shared*) shared_mem;
//Calculate result
int result = (shared_data->a_b)*(shared_data->c_d)-(shared_data->e_f);
printf("Result is %d\n", result);
//Parent detaches from shared memory and deletes
if(shmdt(shared_mem) == -1) exit (EXIT_FAILURE);
if(shmctl(shmid,IPC_RMID,0) == -1) exit(EXIT_FAILURE);
return EXIT_SUCCESS;
}
fork()ing the processes, then waitpid()ing on their return values:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//whatever values you like:
int a = 1;
int b = 2;
int c = 3;
int d = 4;
int e = 15;
int f = 6;
int a_plus_b_pid;
int c_plus_d_pid;
int e_div_f_pid;
int a_plus_b;
int c_plus_d;
int e_div_f;
a_plus_b_pid = fork();
if(a_plus_b_pid)
{
c_plus_d_pid = fork();
if(c_plus_d_pid)
{
e_div_f_pid = fork();
if (e_div_f_pid)
{
//wait for our processes to exit, with our results, and stash the computed values.
waitpid(a_plus_b_pid, &a_plus_b, 0);
waitpid(c_plus_d_pid, &c_plus_d, 0);
waitpid(e_div_f_pid, &e_div_f, 0);
//The 8 least-significant bits carry info that we're not interested in here, so shift them out:
a_plus_b >>= 8;
c_plus_d >>= 8;
e_div_f >>= 8;
printf("%d %d %d %d\n", a_plus_b, c_plus_d, e_div_f, a_plus_b * c_plus_d - e_div_f);
}
else
{
exit (e/f);
}
}
else
{
exit (c+d);
}
}
else
{
exit (a+b);
}
}
This is a version using pthreads:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
volatile int a_b;
volatile int c_d;
volatile int e_f;
const int a=1,b=2,c=3,d=4,e=6,f=2;
void* calc_ab(void*);
void* calc_cd(void*);
void* calc_ef(void*);
int main(){
pthread_t ab_thread, cd_thread, ef_thread;
pthread_create(&ab_thread,NULL,calc_ab,NULL);
pthread_create(&cd_thread,NULL,calc_cd,NULL);
pthread_create(&ef_thread,NULL,calc_ef,NULL);
pthread_join(ab_thread, NULL);
pthread_join(cd_thread, NULL);
pthread_join(ef_thread,NULL);
int result = a_b*c_d-e_f;
printf("Result is %d\n", result);
return EXIT_SUCCESS;
}
void* calc_ab(void* arg){ a_b = a+b;pthread_exit(NULL);}
void* calc_cd(void* arg){ c_d = c+d;pthread_exit(NULL);}
void* calc_ef(void* arg){ e_f = e/f;pthread_exit(NULL);}
To compile you have to link against pthread:
gcc pthread.c -lpthread -o teste
Notes
Note that variables that are shared between the main thread and a child thread are declared volatile. This prevent the compiler of doing some memory optimizations that could prevent a write done in one thread not to be seen by others.
Each child thread writes to a different shared variable. I wanted to keep the code simple, not having to handle synchronization explicitly.
The main thread only reads the shared variable only after it has returned from a pthread_join for the thread that changed it. Again I wanted to keep the code simple, not having to handle synchronization explicitly.
First, you don't need processes at all to do arbitrary computation. Emabedding an interpreter like e.g. lua might be simpler.
Of course, each process has its own address space. Type cat /proc/self/maps to get information about the process running that cat command.
If you insist on using processes to learn how they can communicate thru pipes, you might use something like popen(3) which will use some syscalls to start and pipe a command.
char cmd[80];
int a, b, sum;
/// fill a & b
snprintf (cmd, sizeof(cmd), "echo $[%d + %d]", a, b);
FILE* pcmd = popen(cmd, "r");
if (fscanf (pcmd, "%d", &sum)>0) {
// do something with sum
};
pclose(pcmd);
And you should read a good book like Advanced Unix Programming and Advanced Linux Programming. The real thing is to understand syscalls like fork(2), waitpid(2), execve(2), pipe(2), dup(2), etc.... To understand what syscalls(2) are done by some command or program, use strace