Permission denied issue in mmap function in shared memory in C - c

In the child process the mapping is giving me issue. the parent is creating a shared memory and child is using it for writing a message to parent but when the mmap executes, it gives an error of permission denied. kindly help me to get rid of this issue. everything else is running file. when I try to create shared memory in child process the issue is resolved but the requirement is creating shared memory in parent process, that is why it is taking time to solve it.
/**
* Simple program demonstrating shared memory in POSIX systems.
*
* This is the consumer process
*
* Figure 3.18
*
* To compile, enter
* gcc shm-posix-consumer.c -lrt
*
* #author Gagne, Galvin, Silberschatz
* Operating System Concepts - Tenth Edition
* Copyright John Wiley & Sons - 2018
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 4096;
const char *name = "OS";
//shm_unlink(name);
int shm_fd;
void *ptr;
pid_t pid;
pid=fork();
if(pid==-1) {
printf("Error in creating a child process\n");
return -1;
}
else if(pid==0) {
sleep(2);
printf("child process is executing\n");
/* open the shared memory segment */
shm_fd = shm_open(name, O_RDWR, S_IRWXU);
if (shm_fd == -1) {
printf("opening of shared memory failed\n");
exit(-1);
}
if(ftruncate(shm_fd,SIZE)==-1){
printf("Error in configuring the size of shared memory");
exit(1);
}
/* now map the shared memory segment in the address space of the process */
ptr = mmap(0,SIZE,PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED) {
perror("Map failed in child process\n");
printf("error:%s %d",strerror(errno),errno);
return -1;
}
char *message0;
strcpy(message0,"Greeting to parent");
printf("Message to parent from child:%s\n",message0);
sprintf(ptr,"%s",message0);
ptr += strlen(message0);
if(munmap(ptr,SIZE)==-1){
printf("munmap error:\n");
exit(1);
}
close(shm_fd);
}
else {
printf("parent process is executing\n");
/* create the shared memory segment */
shm_fd = shm_open(name, O_CREAT | O_RDWR, S_IRWXU);
/* configure the size of the shared memory segment */
if(ftruncate(shm_fd,SIZE)==-1){
printf("Error in configuring the size of shared memory");
exit(1);
}
printf("parent process wait after creating shared memory\n");
wait(NULL);
printf("back to parent process after child termination\n");
/* now map the shared memory segment in the address space of the process */
ptr = mmap(0,SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED) {
printf("Map failed in parent\n");
return -1;
}
printf("%s\n",(char *)ptr);
if (shm_unlink(name) == -1) {
printf("Error removing %s\n",name);
exit(-1);
}
}
return 0;
}

At least three problems:
char *message0;
strcpy(message0,"Greeting to parent");
You are using message0 uninitialized, switch to something like
char message0[64];
strcpy(message0,"Greeting to parent");
or simply:
char *message0 = "Greeting to parent";
Here:
void *ptr;
...
ptr += strlen(message0);
You can't use pointer arithmetic with void *, switch to char *ptr;
And here:
ptr += strlen(message0);
if(munmap(ptr,SIZE)==-1){
you need to rewind ptr to the original position returned by mmap before calling munmap, it seems that you can remove this line:
ptr += strlen(message0);
Now it works for me adding #define _XOPEN_SOURCE 500 at the very beginning (for ftruncate).

Related

How to create shared memory after fork?

My code is
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
int main() {
char parent[] = "parent";
char child[] = "child";
char *shmem = (char*)mmap(NULL, 1000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
char *shmem_child = "NOT CHANGE";
memcpy(shmem, parent, sizeof(parent));
int pid = fork();
if (pid == 0) {
char child_new[] = "new child";
printf("Child read: %s\n", shmem);
memcpy(shmem, child, sizeof(child));
printf("Child wrote: %s\n", shmem);
shmem_child = (char*)mmap(NULL, 1000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
memcpy(shmem_child, child_new, sizeof(child_new));
printf("Child create: %s\n", shmem_child);
} else {
printf("Parent read: %s\n", shmem);
sleep(1);
printf("After 1s, parent read: %s\n", shmem);
printf("After 1s, parent read shmem_child: %s\n", shmem_child);
}
}
And the output is
Parent read: parent
Child read: parent
Child wrote: child
Child create: new child
After 1s, parent read: child
After 1s, parent read shmem_child: NOT CHANGE
As you can see, the shared memory(shmem) created before fork works, but the shared memory(shmem_child) created inside child does not work.
Am I doing something wrong? How can I create shared memory inside child so that parent and even brothers(other children of same parent) can access?
Anonymous shared memory stays shared across a fork().
So, both the parent and the child(ren) should access the same memory area, shmem.
You cannot create anonymous shared memory in a child process, and have it magically appear in the parent process. Anonymous shared memory must be created in the parent; then it will be accessible to all children.
You can create non-anonymous shared memory, via e.g. shm_open(). The creator ftruncate()s it to appropriate length, and all processes memory-map the descriptor. You do need to remember to remove the shared memory when no longer needed, via shm_unlink().
Here is a simple (tested and verified) example of anonymous shared memory between a parent and a child:
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
/* SPDX-License-Identifier: CC0-1.0 */
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
typedef struct {
char message[256];
} shared_mem;
static size_t page_aligned(const size_t size)
{
const size_t page = sysconf(_SC_PAGESIZE);
if (size <= page)
return page;
else
return page * (size_t)(size / page + !!(size % page));
/* !!(size % page) is 0 if size is a multiple of page, 1 otherwise. */
}
int child_process(shared_mem *shared)
{
printf("Child: shared memory contains \"%s\".\n", shared->message);
fflush(stdout);
snprintf(shared->message, sizeof shared->message, "Child");
printf("Child: changed shared memory to \"%s\".\n", shared->message);
fflush(stdout);
return EXIT_SUCCESS;
}
int main(void)
{
const size_t size = page_aligned(sizeof (shared_mem));
shared_mem *shared;
pid_t child, p;
shared = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, (off_t)0);
if (shared == MAP_FAILED) {
fprintf(stderr, "Cannot map %zu bytes of shared memory: %s.\n", size, strerror(errno));
return EXIT_FAILURE;
}
snprintf(shared->message, sizeof shared->message, "Parent");
printf("Parent: set shared memory to \"%s\".\n", shared->message);
fflush(stdout);
/* Create the child process. */
child = fork();
if (!child) {
/* This is the child process. */
return child_process(shared);
} else
if (child == -1) {
fprintf(stderr, "Cannot create a child process: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* This is the parent process. */
/* Wait for the child to exit. */
do {
p = waitpid(child, NULL, 0);
} while (p == -1 && errno == EINTR);
if (p == -1) {
fprintf(stderr, "Cannot reap child process: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* Describe the shared memory, */
printf("Parent: shared memory contains \"%s\".\n", shared->message);
fflush(stdout);
/* and tear it down. Done. */
munmap(shared, size);
return EXIT_SUCCESS;
}
Save it as e.g. example.c, then compile and run it via e.g.
gcc -Wall -Wextra -O2 example1.c -o ex1
./ex1
It will output
Parent: set shared memory to "Parent".
Child: shared memory contains "Parent".
Child: changed shared memory to "Child".
Parent: shared memory contains "Child".
showing that this indeed works.
To create shared memory after fork(), or between unrelated processes, all processes have to agree on the name. For POSIX shared memory objects (that you obtain a descriptor to using shm_open(), the name must start with a slash.
Note that I used mode 0600, which corresponds to (decimal 384) -rw-------, i.e. only accessible to processes running as the same user.
Consider the following example:
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
/* SPDX-License-Identifier: CC0-1.0 */
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
typedef struct {
pid_t changer;
time_t when;
char message[256];
} shared_mem;
static size_t page_aligned(const size_t size)
{
const size_t page = sysconf(_SC_PAGESIZE);
if (size <= page)
return page;
else
return page * (size_t)(size / page + !!(size % page));
/* !!(size % page) is 0 if size is a multiple of page, 1 otherwise. */
}
enum {
ACTION_NONE = 0,
ACTION_CREATE = (1<<0),
ACTION_REMOVE = (1<<1),
ACTION_MODIFY = (1<<2),
};
int main(int argc, char *argv[])
{
const size_t size = page_aligned(sizeof (shared_mem));
shared_mem *shared;
const char *name;
time_t now;
const char *message = NULL;
int action = ACTION_NONE;
int arg, shm_fd;
if (argc < 2 || argc > 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *argv0 = (argc > 0 && argv && argv[0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
fprintf(stderr, " %s /NAME [ +CREATE ] [ MESSAGE ] [ -REMOVE ]\n", argv0);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
/* Grab and check name */
name = argv[1];
if (name[0] != '/' || name[1] == '\0') {
fprintf(stderr, "%s: Shared memory name must begin with a slash.\n", argv[1]);
return EXIT_FAILURE;
}
/* Check other command-line parameters. */
for (arg = 2; arg < argc; arg++) {
if (argv[arg][0] == '+') {
action |= ACTION_CREATE;
if (argv[arg][1] != '\0') {
message = argv[arg] + 1;
action |= ACTION_MODIFY;
}
} else
if (argv[arg][0] == '-') {
action |= ACTION_REMOVE;
if (argv[arg][1] != '\0') {
message = argv[arg] + 1;
action |= ACTION_MODIFY;
}
} else
if (argv[arg][0] != '\0') {
if (message) {
fprintf(stderr, "%s: Can only set one message (already setting '%s').\n", argv[arg], message);
return EXIT_FAILURE;
}
message = argv[arg];
action |= ACTION_MODIFY;
}
}
if (action & ACTION_CREATE) {
/* Create the shared memory object. */
shm_fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (shm_fd == -1) {
fprintf(stderr, "%s: Cannot create shared memory object: %s.\n", name, strerror(errno));
return EXIT_FAILURE;
}
/* Resize it to desired size. */
if (ftruncate(shm_fd, (off_t)size) == -1) {
fprintf(stderr, "%s: Cannot resize shared memory object to %zu bytes: %s.\n", name, size, strerror(errno));
close(shm_fd);
shm_unlink(name);
return EXIT_FAILURE;
}
} else {
/* Open an existing shared memory object. */
shm_fd = shm_open(name, O_RDWR, 0600);
if (shm_fd == -1) {
fprintf(stderr, "%s: Cannot open shared memory object: %s.\n", name, strerror(errno));
return EXIT_FAILURE;
}
}
/* Map the shared memory object. */
shared = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, shm_fd, (off_t)0);
if (shared == MAP_FAILED) {
fprintf(stderr, "%s: Cannot map %zu bytes of shared memory object: %s.\n", name, size, strerror(errno));
close(shm_fd);
if (action & (ACTION_CREATE | ACTION_REMOVE))
shm_unlink(name);
return EXIT_FAILURE;
}
/* The shared memory object descriptor is no longer needed. */
if (close(shm_fd) == -1) {
fprintf(stderr, "Warning: Error closing shared memory object: %s.\n", strerror(errno));
}
/* Current time in UTC */
now = time(NULL);
/* If we created it, we need to initialize it too. */
if (action & ACTION_CREATE) {
shared->changer = getpid();
shared->when = now;
snprintf(shared->message, sizeof shared->message, "Initialized");
}
/* Show contents. */
printf("Shared memory was last changed %ld seconds ago by process %ld to '%s'.\n",
(long)(now - shared->when), (long)(shared->changer), shared->message);
fflush(stdout);
/* Modify contents. */
if (action & ACTION_MODIFY) {
printf("Changing shared memory contents into '%s'.\n", message);
fflush(stdout);
shared->changer = getpid();
shared->when = now;
snprintf(shared->message, sizeof shared->message, "%s", message);
}
/* Unmap shared memory object. */
munmap(shared, size);
/* Remove shared memory? */
if (action & ACTION_REMOVE) {
if (shm_unlink(name) == -1) {
fprintf(stderr, "Warning: %s: Cannot remove shared memory object: %s.\n", name, strerror(errno));
return EXIT_FAILURE;
} else {
printf("%s: Shared memory object removed successfully.\n", name);
fflush(stdout);
}
}
/* All done. */
return EXIT_SUCCESS;
}
Save it as e.g. example2.c, and compile it using e.g.
gcc -Wall -Wextra -O2 example2.c -lrt -o ex2
Open up multiple windows. In one, run
./ex2 /myshared +
to create the shared memory; and in others, run
./ex2 /myshared newmessage
When you are done, remember to remove the shared memory object using
./ex2 /myshared -

Exec Family Usage in C

I am beginner in C language. I have a question and the question is only about my curiosity. I have done a task recently. The fallowing code calculates time of process between parent and child. I am taking command
like ls,pwd etc. via input. As a sample, while the code calculates time of -ls command, it does not calculate ls -l. I know I need to change execlp but I do not know which one is better according to that exec family ? In other words, How can I integrate true exec() family type to my code ? Could you help me ?
My example output for ls :
ls
a.out main.c
2006152 ms
My output for ls -l:
ls -l
Error exec: No such file or directory
My codes :
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#define N 20
void ChildProcess();
void ParentProcess();
struct timeval start, end;
char *input;
int main (int argc,char **argv) {
input = argv[1];
pid_t pid;
pid = fork();
if (pid == 0){
ChildProcess ();
}
else {
wait (NULL);
ParentProcess ();
}
return 0;
}
void ChildProcess () {
/* the size (in bytes) of shared memory object */
const int SIZE = 4096;
/* name of the shared memory object */
const char* name = "OS";
/* shared memory file descriptor */
int shm_fd;
/* pointer to shared memory obect */
long int* ptr;
/* create the shared memory object */
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
ptr =(long int*)mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
gettimeofday(&start, NULL);
printf("%ld ",start.tv_usec);
*ptr=start.tv_usec;
if (execlp (input, "", (char *) 0) < 0)
{
perror ("Error exec");
exit (0);}
}
}
void ParentProcess () {
/* the size (in bytes) of shared memory object */
const int SIZE = 4096;
/* name of the shared memory object */
const char* name = "OS";
/* shared memory file descriptor */
int shm_fd;
/* pointer to shared memory object */
long int* ptr;
/* open the shared memory object */
shm_fd = shm_open(name, O_RDONLY, 0666);
/* memory map the shared memory object */
ptr =(long int*)mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
/* read from the shared memory object */
printf("%ld usec okunan\n ", *ptr);
long int start_usec = *ptr;
/* remove the shared memory object */
shm_unlink(name);
gettimeofday(&end,NULL);
printf("%ld son : ",end.tv_usec);
printf ("Total time : %ld %s dir \n", end.tv_usec-start_usec, "ms");
}
You are responsible for writing code to split up the input string up into separate arguments that you can pass to execvp:
/* Take your string "ls -l" and split it up into an array like this: */
char* split[3];
split[0] = "ls";
split[1] = "-l";
split[2] = NULL;
execvp(split[0], split);
If you don't know how to split strings in C to make this happen, you will have to research and learn that separately.
Alternatively, you can ask a shell to do it for you. However, this will also measure the startup and processing time of the shell:
char* command = "ls -l";
execlp("sh", "sh", "-c", command, NULL);

Program stuck in while loop

I was trying to use semaphores in a while loop and my program is running in an infinite loop. Basically I fork off children and use execv to start new user processes. The processes use semaphore in shared memory to communicate.
struct shared
{
int count;
sem_t sem;
} *shmem;
void forking()
{
key_t shmkey = ftok("makefile",777);
if (shmkey == -1) {
perror("Ftok failed");
exit(-1);
}
// Get our shm id
shmid = shmget(shmkey, sizeof(shared), 0666 | IPC_CREAT);
if (shmid == -1) {
perror("Failed to allocate shared memory region");
exit(-1);
}
// Attach to our shared memory
shmem = (shared*)shmat(shmid, (void *)0, 0);
if (shmem == (void *)-1) {
perror("Failed to attach to shared memory region");
exit(-1);
}
sem_init(&(shmem->sem),1,1);
pid_t PID;
int i;
for(i=0;i<4;i++)
{
PID=fork();
if(PID==0)
{
static char *args[]={"./child",NULL};
int status;
if(( status= (execv(args[0], args)))==-1)
perror("failed to execv");
exit(EXIT_FAILURE);
}
if(PID>0)
{
while(1)
{
sem_wait(&(shmem->sem));
{
shmem->count=shmem->count+1;
}
sem_post(&(shmem->sem));
}
}
if(PID<0)
perror("error in fork");
}
}
main()
{
forking();
}
in child.c
struct shared
{
int count;
sem_t sem;
} shmem;
void main()
{
bool alive=true;
do
{
sem_wait(&(shmem->sem));
if(shmem->count==5)
{
shmem->count=0;
alive=false;
}
sem_post(&(shmem->sem));
}while(alive);
}
child.c loops endlessly without allowing parent to increment i till 5. This happens even if I comment out while loop in first file and just let it increment without loops.In the end nothing exits.
You are using fork wrong, and definitely not using shared memory.
Here's some few point
By calling fork, you are making a copy of parent running in different memory space. http://man7.org/linux/man-pages/man2/fork.2.html
By using execve, you essentially delete the old memory and replace it with a new one which are not linked in anyway to your parent process. http://man7.org/linux/man-pages/man2/execve.2.html
To make your code work, you should be using pthread_* instead as it will live in the same memory space and make your global variable volatile as gcc will try to optimize and will have weird behaviors if it does so.
Ok it seems I've missed quite a few points while being not totally wrong on my assumption.
So your child.c is missing quite a few bit of code
It does not contains all the initialization you've made in your parent which is necessary because if you use execve you essentially lost every memory mapping you've mapped previously in your parent process.
Your parents loops infinitely so shmem->count will never really equals to 5, you will have to break at some moment or change your condition in your child code.
Here's what your child should look like.
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct
{
int count;
sem_t sem;
} shared;
shared *shmem;
int shmid;
key_t shmkey;
int main()
{
int alive=1;
shmkey = ftok("makefile",777);
if (shmkey == -1) {
perror("Ftok failed");
exit(-1);
}
// Get our shm id
shmid = shmget(shmkey, sizeof *shmem, 0);
if (shmid == -1) {
perror("Failed to allocate shared memory region");
exit(-1);
}
// Attach to our shared memory
shmem = (shared*)shmat(shmid, (void *)0, 0);
if (shmem == (shared *)-1) {
perror("Failed to attach to shared memory region");
exit(-1);
}
do
{
sem_wait(&(shmem->sem));
printf("%d\n", shmem->count);
if(shmem->count > 5)
{
shmem->count=0;
alive=0;
}
sem_post(&(shmem->sem));
}while(alive);
printf("I have finished %u\n", getpid());
exit(0);
}

synchronisation problem in multiple threads of multiple processes

I have a code. There are 2 processes. Parent is writer on file a.txt. Child is reader on a.txt.Parent has 2 threads and child has 2 threads. Parent's 1st thread opens a file parent1.txt . reads 128 chars. writes to a.txt.Parent's 2nd thread opens file parent2.txt.reads 128 chars. writes to a.txt. Child's 1st thread reads 128 chars from a.txt and writes to child1.txt. child's 2nd thread reads 128 chars from a.txt and child2.txt. Any parent thread , after writing, should generate event and invoke the child's reader threads.I have implemented a solution using mutex and condition variable.Parent's writer threads generate pthread_cond_signal after writing to a.txt. 1>But child's reader threads are not running after that. both parent threads are running in loop.2>Parent reads frm parent1.txt. the fread is successfull. But when it writes to a.txt, it is not successfull. the a.txt file is always empty.I think mutex can not be use between multiple processes. That may be 1 problem
My code is as follows
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
FILE*fd,*fdRead1,*fdRead2,*fdWrite1,*fdWrite2;
pthread_mutex_t *mut1;
pthread_mutexattr_t attrmutex;
pthread_cond_t *cond_var;
pthread_condattr_t attrcond;
#define OKTOWRITE "/condwrite"
#define MESSAGE "/msg"
#define MUTEX "/mutex_lock"
void* R1(void *)
{
char buf[128];
int size;
fdWrite1 = fopen("child1.txt","w+");
cout<<"R1Thread"<<endl;
for(int i=0;i<10;i++)
{
cout<<"R1Thread-1"<<endl;
pthread_mutex_lock(mut1);
pthread_cond_wait(cond_var,mut1);
cout<<"R1Thread-2"<<endl;
size = fread(buf,128,1,fd);
fwrite(buf,size,1,fdWrite1);
pthread_mutex_unlock(mut1);
}
fclose(fdWrite1);
}
void* R2(void *)
{
char buf[128];
int size;
fdWrite2 = fopen("child2.txt","w+");
cout<<"R2Thread"<<endl;
for(int i=0;i<10;i++)
{
cout<<"R2Thread-1"<<endl;
pthread_mutex_lock(mut1);
pthread_cond_wait(cond_var,mut1);
cout<<"R2Thread-2"<<endl;
size = fread(buf,128,1,fd);
fwrite(buf,size,1,fdWrite2);
pthread_mutex_unlock(mut1);
}
fclose(fdWrite2);
}
void* W1(void *)
{
char buf[128];
int size;
fdRead1 = fopen("parent1.txt","r");
for(int i=0;i<10;i++)
{
pthread_mutex_lock(mut1);
size = fread(buf,128,1,fdRead1);
fwrite(buf,size,1,fd);
pthread_cond_signal(cond_var);
cout<<"W2Thread-1"<<endl;
pthread_mutex_unlock(mut1);
sleep(10);
}
fclose(fdRead1);
}
void* W2(void *)
{
char buf[128];
int size;
fdRead2 = fopen("parent2.txt","r");
for(int i=0;i<10;i++)
{
pthread_mutex_lock(mut1);
size = fread(buf,128,1,fdRead2);
fwrite(buf,size,1,fd);
pthread_cond_signal(cond_var);
cout<<"W2Thread-1"<<endl;
pthread_mutex_unlock(mut1);
sleep(1000);
}
fclose(fdRead2);
}
int main()
{
int des_cond, des_msg, des_mutex;
int mode = S_IRWXU | S_IRWXG;
des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_mutex < 0) {
perror("failure on shm_open on des_mutex");
exit(1);
}
if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
mut1 = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),
PROT_READ | PROT_WRITE, MAP_SHARED, des_mutex, 0);
if (mut1 == MAP_FAILED ) {
perror("Error on mmap on mutex\n");
exit(1);
}
des_cond = shm_open(OKTOWRITE, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_cond < 0) {
perror("failure on shm_open on des_cond");
exit(1);
}
if (ftruncate(des_cond, sizeof(pthread_cond_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
cond_var = (pthread_cond_t*) mmap(NULL, sizeof(pthread_cond_t),
PROT_READ | PROT_WRITE, MAP_SHARED, des_cond, 0);
if (cond_var == MAP_FAILED ) {
perror("Error on mmap on condition\n");
exit(1);
}
/* Initialise attribute to mutex. */
pthread_mutexattr_init(&attrmutex);
pthread_mutexattr_setpshared(&attrmutex, PTHREAD_PROCESS_SHARED);
/* Allocate memory to pmutex here. */
/* Initialise mutex. */
pthread_mutex_init(mut1, &attrmutex);
/* Initialise attribute to condition. */
pthread_condattr_init(&attrcond);
pthread_condattr_setpshared(&attrcond, PTHREAD_PROCESS_SHARED);
/* Allocate memory to pcond here. */
/* Initialise condition. */
pthread_cond_init(cond_var, &attrcond);
pthread_t thR1,thR2,thW1,thW2;
fd = fopen("a.txt","w+");
int res = fork();
if(res<0) perror("error forking\n");
if(res==0)//child
{
cout<<"child created"<<endl;
pthread_create(&thR1,0,R1,0);
//pthread_create(&thR2,0,R2,0);
pthread_join(thR1,0);
//pthread_join(thR2,0);
fclose(fd);
}
else//parent
{
//fdRead = fopen("parent.txt","r");
pthread_create(&thW1,0,W1,0);
//pthread_create(&thW2,0,W2,0);
pthread_join(thW1,0);
//pthread_join(thW2,0);
fclose(fd);
wait(0);
}
}
The output is as follows-
child created
W2Thread-1
R1Thread
R1Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
The condition_wait in child never comes out.
There are potential issues with using multiple processes, each with multiple threads, but they mostly revolve around program state at the time of the fork. Since your program forks before it creates any additional threads, you can be confident about its state at that time, and in particular, you can be confident that its one thread is not at that time executing in a critical section. This is fine.
However, you are missing two key details:
Although you set the mutex to be process-shared, the version of the code you initially presented failed to do the same for the condition variable.
Setting pthread_* synchronization objects to be process-shared is necessary, but not sufficient, for inter-process use. For that, you need the synchronization objects to reside in shared memory accessed by all participating processes. Only that way can all the process access the same objects.

One Process per Client Server using Shared Memory in C

I am creating an "One Process per Client" server using the TCP protocol for academic purpose.
I use a global struct like the one bellow:
struct keyvalue
{
char a[4096];
char b[4096];
}data[1000];
I use fork() to create a child for each client.
I know that each child sees this struct as an exact copy of the parent process however if a child makes a change it is not visible to the other children and this is my goal.
I searched in google for hours and the only proper solution i found is mmap()
Bellow I present how i tried to solve this task:
int main ( int argc, char *argv[])
{
for(int c = 0; c < 1000 ; c++)
{
data[c] = mmap(NULL, sizeof(data[c]), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
}
.
.
.
return 0;
}
However I think that I haven't understand properly the use of this function and the documentation didn't help for this project.
It would be great if someone explained to me the exact way to use this function for my project.
EDIT:
This global struct is used by two global function:
void put(char *key, char *value)
{
.
.
.
strcpy(data[lp].keys,key);
strcpy(data[lp].values,value);
.
.
.
}
Thank you in behave and sorry for my bad English.
You can use the following piece of code to create an array of structs that is shared across multiple forked processes.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define MAX_LEN 10000
struct region {
int len;
char buf[MAX_LEN];
};
int fd;
int main(void){
//Create shared memory
fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
printf("Error: shm_open\n");
//Expand to meet the desirable size
if (ftruncate(fd, MAX_LEN*sizeof(struct region)) == -1)
printf("Error: ftruncate\n");
pid_t pid = fork();
if (pid == 0){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
printf("Error\n");
memset(ptr, 0, 50*sizeof(struct region));
usleep(1500000);
ptr[33].len = 42;
}else if (pid > 0){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
printf("Error\n");
usleep(1000000);
printf("Value before: %d\n", ptr[33].len);
usleep(1000000);
printf("Value after: %d\n", ptr[33].len);
}else{
printf("Error: fork\n");
}
shm_unlink("/myregion");
return 0;
}
Compilation: gcc -o shmem_test shmem_test.c -lrt
EDIT: If you can't use shm_open, alternatively you can do the following in your main function:
int main(void){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED,-1,0);
pid_t pid = fork();
if (pid == 0){
usleep(1500000);
ptr[33].len = 42;
}else if (pid > 0){
usleep(1000000);
printf("Value before: %d\n", ptr[33].len);
usleep(1000000);
printf("Value after: %d\n", ptr[33].len);
}else{
printf("Error: fork\n");
}
return 0;
}
The difference between the two, is that shm_open creates a named shared memory, which means that different processes in different executables can map this memory, given that they have the struct region definition. In the second case this cannot be done, i.e the shared memory is anonymous.

Resources