I want the following: first the parent process prints "hello", then the child process prints "world" and this is done 3 times. When I execute my code I only get hello world once but I want to get it printed 3 times.
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char*argv[]){
char* parent="hello ";
char* child="world";
sem_t *sem = sem_open("/mysem", O_CREAT, 0644, 1);
sem_t *sem1=sem_open("/mysem1", O_CREAT, 0644, 0);
int pid=fork();
if(pid<0){
printf("error in forking");
return -1;
}
int cnt=0, cnt1=0;
if(pid==0){
sem_wait(sem1);
write(1, child, strlen(child));
cnt++;
if(cnt1<3){
sem_post(sem);
}
}else{
sem_wait(sem);
write(1, parent, strlen(parent));
cnt++;
if(cnt<3){
sem_post(sem1);
}
}
return 0;
}
maybe try this :
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#define BUFFER_SIZE 7
int main(int argc, char **argv)
{
char parent[BUFFER_SIZE] = "hello ";
char child[BUFFER_SIZE] = "world\n";
sem_t *sem = sem_open("/mysem", O_CREAT, 0644, 1);
sem_t *sem1 = sem_open("/mysem1", O_CREAT, 0644, 0);
int cnt = 0;
int pid = fork();
if (sem == SEM_FAILED || sem1 == SEM_FAILED) {
printf("Error : sem_open() call failed.\n");
return (-1);
}
if (pid < 0) {
printf("error in forking");
return (-1);
}
if (pid == 0) {
while (cnt < 3) {
sem_wait(sem1);
if (write(1, child, strlen(child)) == -1) {
printf("Error : write call failed.\n");
}
cnt++;
sem_post(sem);
}
}
else {
while (cnt < 3) {
sem_wait(sem);
if (write(1, parent, strlen(parent)) == -1) {
printf("Error : write function failed.\n");
}
cnt++;
sem_post(sem1);
}
}
sem_close(sem);
sem_close(sem1);
return (0);
}
Explanation :
#define BUFFER_SIZE 7 this is a macro, 7 because of part 2.
Memory leaks (use valgrind)
Don't do : char *str = "abc";
but do : char str[string_size + 1] = "abc";
Because char *str = doesn't allocate memory so you will probably get memory leaks, always allocate string_size + 1 with C String. You can use malloc too to allocate your own size.
Put your int cnt variables before the fork(), fork will copy all memory so you can put only one variable before your fork call, for more readable code.
You should always call sem_close() as soon as possible and you should always look for returned value from functions that are not your, use C man, for exmaple "man 2 write" in your linux console (not looking for sem_wait semp_post and sem_close returned value shouldn't be problematic here, but you can still print a message if you want).
Your main problem here is that you should switch your if (cnt < 3) into a loop as i did with while, your parent and child process only course once write() if you don't set a loop.
The most important thing, please look for coding style rules to make your code more redeable.
This is pretty long, but you should take at look in all i said.
Compilation :
gcc file.c -pthread
./a.out
I'm on linux, fedora32.
Output :
hello world
hello world
hello world
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);
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm struggling with shared mem on linux paltform.
Cosider the following code:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#define SEM_NAME "mysem"
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
sleep(1);
}
return 0;
}
If I launch the app for a read only shared memory I get, as expected, segmentation fault the first time *ptr is incremented inside main loop.
I'm working on a lib that abstract Linux shared memory.
This lib will be deployed to third part developers that will implement some processes for my application on an embedded target.
This lib will implement "global variables" between processes. I was wondering if I can avoid to develop get and set function and simply return address of allocated memory.
In case of wrong permission access I want to give to caller infos about what was wrong in its code. Read segmentation fault on terminal and process termination does not give user a good information.
EDIT2
After #Ctx answer I tried the following solution but it works the first segmentation fault. The second trigger standard segmentation fault and pogram terminate.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <setjmp.h>
#define SEM_NAME "mysem"
#define TEST 1
jmp_buf env;
void segvhandler(int arg) {
longjmp(env, 1);
}
bool Test ( int *ptr, sem_t *mutex, pid_t PID)
{
#if (TEST == 1)
signal(SIGSEGV, segvhandler);
#elif (TEST == 2)
sig_t segvhandler_OLD = signal(SIGSEGV, segvhandler);
#endif
int val = setjmp(env);
if (val != 0)
{
printf("Segmentation fault catched.\n");
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return false;
}
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return true;
}
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
Test (ptr, mutex, PID);
sleep(1);
}
return 0;
}
Per the mmap() man page:
Use of a mapped region can result in these signals:
SIGSEGV
Attempted write into a region mapped as read-only.
If you want to proceed if the modification doesn't work, you can install a signal handler for SIGSEGV and use (sig)setjmp/longjmp to continue execution at a defined point:
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
jmp_buf env;
void segvhandler(int arg) {
siglongjmp(env, 1);
}
void somefunc(void) {
char *ptr = NULL;
signal(SIGSEGV, segvhandler);
if (!sigsetjmp(env, 1)) {
// Direct invocation, try the memory access
*ptr++;
}
signal(SIGSEGV, SIG_DFL);
}
int main (void) {
while (1) {
somefunc();
printf("One more iteration...\n");
}
exit(EXIT_SUCCESS); // Never reached
}
sigsetjmp(env, 1) also saves the blocked signals in env, when it's second argument is non-zero and siglongjmp() then restores these. Otherwise, the signal will still be blocked after longjmp(), since it is not a real return from the signal handler.
Keep in mind that you should only have the handler installed directly before you make the memory access in question and deinstall it afterwards.
a few minutes with the debugger shows the program crashes on the call to sem_wait().
if, after the call to sem_open() insert:
if( SEM_FAILED == mutex )
{
perror( "sem_open failed" );
exit( EXIT_FAILURE );
}
then move the statement:
sem_unlink(SEM_NAME);
to before the statement:
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
then it will become obvious that the remaining problem is in this statement:
printf("PID %d Count: %d\n", PID, (*ptr)++);
which causes a bus error signal to be raised. this bus error signal occurs on the very first pass through the while() loop.
there is a simple cause.
the printf() statement, last parameter is trying to both read and write the memory mapped file, but the memory mapping was only for (depending on the command line parameter) either 'PROT_READ' which allows reading or 'PROT_WRITE' which allows writing. the parameter to the call to mmap() needs to include both capabilities AND the call to open() also needs to
have the mode: O_RDWR. (the open() and the mmap() modes need to match
This is the corrected code after Ctx answer. I also found out THIS that is useful to understan why longjmp is not the right solution with signals.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <setjmp.h>
#define SEM_NAME "mysem"
#define TEST 1
jmp_buf env;
void segvhandler(int arg) {
siglongjmp(env, 1);
}
bool Test ( int *ptr, sem_t *mutex, pid_t PID)
{
#if (TEST == 1)
signal(SIGSEGV, segvhandler);
#elif (TEST == 2)
sig_t segvhandler_OLD = signal(SIGSEGV, segvhandler);
#endif
int val = sigsetjmp(env, 1);
if (val != 0)
{
printf("Segmentation fault catched.\n");
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return false;
}
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return true;
}
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
Test (ptr, mutex, PID);
sleep(1);
}
return 0;
}
I need to write a program that is creating a N amount of sub processes and every single one of them adds one to a shared memory variable. My idea is to use semaphores and shared memory, but the processes are not waiting for each other and the shared memory variable is also not working as I want it.
mydefs.h
#ifndef __MYDEFS__H__
#define __MYDEFS__H__
// Includes
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <memory.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/shm.h>
#endif // __MYDEFS__H__
main.c
#include "mydefs.h"
#define PROC_COUNT 3
#define INITAL_MARKER_VALUE 0
#define PID_LEN 32
char mypid[PID_LEN];
int main()
{
int i, shm_id;
sem_t mutex;
if(sem_init(&mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
shm_id = shmget(IPC_PRIVATE, 4*sizeof(int), IPC_CREAT | 0666);
if (shm_id < 0) {
printf("shmget error\n");
}
int *shmpointer = shmat(shm_id,0,0);
memset(mypid, 0, sizeof(mypid));
sprintf(mypid, "%06d", getpid());
for(i = 0; i < PROC_COUNT; i++)
{
if (fork() == 0)
{
while(sem_wait(&mutex)!=0);
execl("slaveproc", "slaveproc", mypid, (char *)0);
shmpointer += 1;
sem_post(&mutex);
perror("\n Can't exec slave program. Cause ");
exit(1);
}
}
sleep(1);
printf("%d\n", *shmpointer);
return 0;
}
slaveproc.c
#include "mydefs.h"
int marker; // Marker value
int main(int argc, char *argv[])
{
master_pid = atoi(argv[1]);
printf("\n --------------------------------------");
printf("\n I'm the slave proc!");
printf("\n My pid: %d", getpid());
printf("\n My master's pid: %d", master_pid);
printf("\n --------------------------------------");
for(;;) pause();
return 0;
}
The problem (or at least "a problem") is that mutex is not in shared memory: it's allocated on the stack. When you fork(), the new process will have a completely separate copy from the old process, so calling sem_wait(&mutex) on one process will not affect the other process's mutex at all.
You should put mutex in the shared memory:
int main()
{
int i, shm_id;
shm_id = shmget(IPC_PRIVATE, sizeof(sem_t) + 4*sizeof(int), IPC_CREAT | 0666);
if (shm_id < 0) {
printf("shmget error\n");
}
int *shmpointer = shmat(shm_id,0,0);
sem_t *mutex = shmpointer;
shmpointer = (void*)shmpointer + sizeof(sem_t);
if(sem_init(mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
memset(mypid, 0, sizeof(mypid));
sprintf(mypid, "%06d", getpid());
for(i = 0; i < PROC_COUNT; i++)
{
if (fork() == 0)
{
while(sem_wait(mutex)!=0);
execl("slaveproc", "slaveproc", mypid, (char *)0);
shmpointer += 1;
sem_post(mutex);
perror("\n Can't exec slave program. Cause ");
exit(1);
}
}
sleep(1);
printf("%d\n", *shmpointer);
return 0;
}
You're also never writing to the memory in shmpointer (perhaps you meant (*shmpointer) += 1?), but I'll let you figure that out on your own.
I'm facing a synchronization problem, the problem I'm trying to solve involves sending string from parent to child, reversing it and sending it back to child ( using shared memory ).
However to make sure child is waiting for parent I'm using sleep(3) to give 3 seconds to parent process to enter string, however this is limiting my programs efficiency, I don't want to force user to wait for 3 seconds.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h> /* Needed for the wait function */
#include <unistd.h> /* needed for the fork function */
#include <string.h> /* needed for the strcat function */
#define SHMSIZE 27
int main() {
int shmid;
char *shm;
if(fork() == 0) {
sleep(3);
shmid = shmget(29009, SHMSIZE, 0);
shm = shmat(shmid, 0, 0);
printf ("Child : Reading %s \n",shm) ;
int len=strlen(shm);
char rev[100],temp;
int i = 0;
int j = strlen(shm) - 2;
while (i < j) {
temp = shm[i];
shm[i] = shm[j];
shm[j] = temp;
i++;
j--;
}
shmdt(shm);
}else {
shmid = shmget(29009, SHMSIZE, 0666 | IPC_CREAT);
shm = shmat(shmid, 0, 0);
printf("Parent : Enter String \n ");
char *s = (char *) shm;
*s = '\0';
char a[100];
fgets(a,100,stdin);
strcat(s,a);
printf ("Parent: sending %s \n",shm);
sleep(3);
printf("Parent: receiving %s" ,shm);
shmdt(shm);
}
return 0;
}
Question:
How could this be implemented in a better way, so that the program is more efficient?
I would suggest using semaphores, this is not a case where you use 'sleep':
http://man7.org/linux/man-pages/man7/sem_overview.7.html
You can use them like in this example:
http://www.csc.villanova.edu/~mdamian/threads/posixsem.html
You cannot know for sure that it will not take more than 3 seconds, so sleep is a realy bad choice. So, it goes something like this:
#include <stdio.h>
#include <semaphore.h>
int main(void)
{
sem_t *sem = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_ANONYMOUS, -1, 0);
sem_init(sem, 1, 1);
if(fork() == 0) {
printf("Child: Waiting to acquire semaphore\n");
sem_wait(sem);
printf("Child acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem);
} else {
printf("Parent: Waiting to acquire semaphore\n");
sem_wait(sem);
printf("Parent acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem);
}
sem_destroy(sem);
return 0;
}
Oh and if you want it parent to be followed by child always (or the other way around), you can use two semaphores, and initialize them accordingly(with 1 and 0, or 0 and 1).
sem_wait(sem1);
printf("Parent acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem2);
/* Other things will be happening here */
sem_wait(sem2);
printf("Child acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem1);
Edit
If you do not have to use shared memory, it would be better to do the communication with sockets.
Thanks to amazing StackOverflow community for coming to my rescue! I have resolved solved the issue using semaphores! I'm sharing my final code so it can be of use for anyone who gets struck in a situation like mine!
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h> /* Needed for the wait function */
#include <unistd.h> /* needed for the fork function */
#include <string.h> /* needed for the strcat function */
#include <semaphore.h>
#include <sys/mman.h>
#include<fcntl.h>
#include<stdlib.h>
#define SHMSIZE 27
typedef struct {
sem_t one;
sem_t two;
} SemPair;
int main() {
int shm = shm_open("/test", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(shm, sizeof(sem_t));
SemPair *sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
sem_init(&(sem->one), 1, 0);
sem_init(&(sem->two), 1, 0);
int shmid;
char *shmz;
if(fork() == 0) {
sem_wait(&(sem->one));
shmid = shmget(29009, SHMSIZE, 0);
shmz = shmat(shmid, 0, 0);
printf ("Child : Reading %s \n",shmz) ;
int len=strlen(shmz);
char rev[100],temp;
int i = 0;
int j = strlen(shmz) - 2;
while (i < j) {
temp = shmz[i];
shmz[i] = shmz[j];
shmz[j] = temp;
i++;
j--;
}
shmdt(shmz);
sem_post(&(sem->two));
}
else {
shmid = shmget(29009, SHMSIZE, 0666 | IPC_CREAT);
shmz = shmat(shmid, 0, 0);
printf("Parent : Enter String \n ");
char *s = (char *) shmz;
*s = '\0';
char a[100];
fgets(a,100,stdin);
strcat(s,a);
printf ("Parent: sending %s \n",shmz);
sem_post(&(sem->one));
sem_wait(&(sem->two));
printf("Parent: receiving %s" ,shmz);
shmdt(shmz);
}
return 0;
}
what I want is this:
1 main process that create 4 children process where:
-> The main process receive messages from the children through the queue and print the message recieved.
-> The children send messages (a string with priority+message) through the queue and finish.
All in a while (1), so, when you CTRL+C, the children finish first (the signal is in the children code) and then, the parent finish.
For the moment, I am having problem with mq_send() and mq_recieve().
Well, this is my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
void sigint_handler()
{
/*do something*/
printf("killing process %d\n",getpid());
exit(0);
}
int main ()
{
mqd_t mqd;
struct mq_attr atributos;
// atributos.mq_maxmsg = 10;
//
// atributos.mq_msgsize = 50;
printf ("This is the parent. PID=%d\n",getpid ());
int num_children = 4;
int i;
int pid;
int status;
char buffer [50];
while (1){
for (i=0; i<num_children ;i++){
if ((pid=fork()==0)){
signal(SIGINT, sigint_handler);
int prio = rand () % 3;
printf ("%d\n",prio);
char * msg= "Hi dude";
char * priority=NULL;
if (prio == 0){
priority = "NORMAL";
}
else {
priority = "URGENT";
}
char* toSend=NULL;
toSend = malloc(strlen(msg)+1+strlen(priority));
strcpy (toSend,priority);
strcat (toSend,msg);
printf ("%s\n",toSend);
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
if (mq_send(mqd, msg , strlen(toSend), prio) == -1) {
printf ("Error mq_send\n");
exit (-1);
}
mq_close(mqd);
printf ("This is children %d\n",getpid());
sleep(1);
exit(0);
}
}
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
//Rest Parent code
if (mq_receive(mqd, buffer, strlen(buffer),0)==-1){
printf ("Error mq_recieve\n");
exit(-1);
}
printf("Received: %s\n",buffer);
sleep (1);
waitpid(pid,&status,0);
printf ("This is the parent again %d, children should have finished\n",getpid());
mq_close(mqd);
}
}
I don't know why both mq_send() and mq_receive() returns -1, what am I doing wrong¿?
And you you see something wrong in my code in order to do what I intend apart from the error I am talking about, let me know.
Thank you in advance, I appreciate any help.
user58697 touched upon the biggest problems.
(1) Your queue opens were failing with EINVAL because you wee passing uninitialized attributes because you commented out assignments.
(2) You were opening both queues for write-only. The parent queue needed to be opened in read mode.
(3) Execute permissions don't mean anything to a queue so 777 permissions while not invalid are unnecessary.
(4) Your sends/receives were failing because of invalid lengths. In many if not most cases it is just easier and safer to allocate your buffers to the length attribute of the queue. In this case you know the length before hand but in programs that don't you can get the value via mq_getattr.
(5) You weren't calling srand to seed the RNG before calling rand.
(6) You had a memory leak where you allocate space (unnecessarily) for the message but never freed it.
(7) What you were trying to do with passing priorities is redundant. POSIX MQs have priorities already built in. You can just use those.
I took out some of the fluff (mainly the loops & signals) to concentrate more on the queue aspects of your program.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
int main()
{
srand(time(NULL));
mqd_t mqd;
struct mq_attr atributos = {.mq_maxmsg = 10, .mq_msgsize = 50};
int i;
int pid;
int status;
int num_children = 4;
char buffer[atributos.mq_msgsize];
for (i = 0; i < num_children; i++)
{
if ((pid = fork() == 0))
{
int prio = rand () % 3;
char* msg = "Hi dude";
strncpy (buffer, msg, sizeof(buffer));
if ((mqd = mq_open("/queue.txt", O_CREAT | O_WRONLY, 0666, &atributos)) == -1)
{
perror("child mq_open");
exit(1);
}
if (mq_send(mqd, buffer, sizeof(buffer), prio) == -1)
{
perror("mq_send");
exit(1);
}
mq_close(mqd);
exit(0);
}
}
// parent
if ((mqd = mq_open("/queue.txt", O_CREAT | O_RDONLY, 0666, &atributos)) == -1)
{
perror("parent mq_open");
exit(1);
}
int priority;
for (int i = 0; i < num_children; ++i)
{
if (mq_receive(mqd, buffer, sizeof(buffer), &priority) == -1)
{
perror("mq_recieve");
exit(1);
}
printf("Received (%s): %s\n", (priority == 0) ? "NORMAL" : "URGENT", buffer);
pid_t childpid;
if ((childpid = waitpid(-1, &status, 0)) > 0)
{
if (WIFEXITED(status))
printf("PID %d exited normally. Exit status: %d\n",
childpid, WEXITSTATUS(status));
else
if (WIFSTOPPED(status))
printf("PID %d was stopped by %d\n",
childpid, WSTOPSIG(status));
else
if (WIFSIGNALED(status))
printf("PID %d exited due to signal %d\n.",
childpid,
WTERMSIG(status));
}
}
mq_close(mqd);
}
First and foremost, when a system call fails, print errno (and strerror(errno)).
Now, obvious mistakes:
as was mentioned, you need a read access to be able to mq_receive()
what is strlen(buffer)?
you are passing attributes without initializing them.
To summarize, print errno and see what is wrong.