reading and writing int from/to shared memory in c - c

I'm trying to make a program where a thread writes an integer into a shared memory location and then the other thread reads and prints that integer. the problem I'm facing is that the second thread keeps reading the integer as -1.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
struct args {
void* memptr;
sem_t* semptr;
};
void *p1(void *vargp)
{
void* memory = ((struct args*)vargp)->memptr;
sem_t* semaphore = ((struct args*)vargp)->semptr;
//sem_wait(semaphore);
//sleep(0.5);
for(int i=0; i<=10; i++)
{
if (!sem_wait(semaphore)) {
printf("got in if p1\n");
sprintf(memory, "%d", i);
sem_post(semaphore);
sleep(1);
}
}
if (!sem_wait(semaphore)) {
sprintf(memory, "%d", 0);
sem_post(semaphore);
sleep(1);
}
sleep(0.1);
}
void *p2(void *vargp)
{
void* memory = ((struct args*)vargp)->memptr;
sem_t* semaphore = ((struct args*)vargp)->semptr;
sleep(0.1);
while(1)
{
if (!sem_wait(semaphore)) {
printf("got in if p2\n");
if((int)memory == 0){
break;
}
printf("%d\n", (int)memory);
sem_post(semaphore);
sleep(1);
}
}
}
const int ByteSize = 4;
const char* SharedName = "memNameTest";
const char* SemaphoreName = "semNameTest";
int main()
{
int fd = shm_open(SharedName, O_RDWR, 0644);
ftruncate(fd, ByteSize);
void* memptr = mmap(0, ByteSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sem_t* semptr = sem_open(SemaphoreName, O_CREAT, 0644, 0);
sem_post(semptr);
struct args *Share = (struct args *)malloc(sizeof(struct args));
Share->memptr = memptr;
Share->semptr = semptr;
pthread_t thread1, thread2;
printf("Before Thread\n");
pthread_create(&thread1, NULL, p1, (void*)Share);
pthread_create(&thread2, NULL, p2, (void*)Share);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("After Thread\n");
munmap(memptr, ByteSize);
close(fd);
sem_close(semptr);
unlink(SharedName);
return 0;
exit(0);
}
I have tried changing (int)memory into *((int*)memory) but that resulted in a segmentation error.
(edit)
as suggested I tried this in a single-threaded program and got it to work as follows:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
/* the size (in bytes) of shared memory object */
const int SIZE = 4;
/* name of the shared memory object */
const char* SharedName = "memoryInt";
/* create the shared memory object */
int shm_fd = shm_open(SharedName, O_CREAT | O_RDWR, 0644);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
void* memptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
for(int i=1; i<=10; i++){
/* write to the shared memory object */
//sprintf(memptr, "%d", i);
memcpy(memptr, &i, sizeof(int));
printf("%d\n", *((int*)memptr));
sleep(1);
}
return 0;
}
though this still doesn't work in a multi-threaded program as i get a segmentation fault.
this is the output:
Before Thread
got in if p1
Segmentation fault

First, you have to show what happen on your terminal when you compile your program.
Secondly, the function sprintf has the declaration:
sprintf(char *str, const char *format, ...);
That means the p1 will write the null terminated string of character. In your code, i dont understand why you use the void pointer memory instead of using char pointer as the description. You should verify the read/write function by using single-threaded before applying to the multi-thread.

Related

Cant Share the dynamically allocated memory block created in parent to child process [duplicate]

In fork child, if we modify a global variable, it will not get changed in the main program.
Is there a way to change a global variable in child fork?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int glob_var;
main (int ac, char **av)
{
int pid;
glob_var = 1;
if ((pid = fork()) == 0) {
/* child */
glob_var = 5;
}
else {
/* Error */
perror ("fork");
exit (1);
}
int status;
while (wait(&status) != pid) {
}
printf("%d\n",glob_var); // this will display 1 and not 5.
}
You can use shared memory (shm_open(), shm_unlink(), mmap(), etc.).
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static int *glob_var;
int main(void)
{
glob_var = mmap(NULL, sizeof *glob_var, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*glob_var = 1;
if (fork() == 0) {
*glob_var = 5;
exit(EXIT_SUCCESS);
} else {
wait(NULL);
printf("%d\n", *glob_var);
munmap(glob_var, sizeof *glob_var);
}
return 0;
}
Changing a global variable is not possible because the new created process (child)is having it's own address space.
So it's better to use shmget(),shmat() from POSIX api
Or You can use pthread , since pthreadsare sharing the globaldata and the changes in global variable is reflected in parent.
Then read some Pthreads tutorial.
Here is an alternative solution.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
typedef struct
{
int id;
size_t size;
} shm_t;
shm_t *shm_new(size_t size)
{
shm_t *shm = calloc(1, sizeof *shm);
shm->size = size;
if ((shm->id = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0)
{
perror("shmget");
free(shm);
return NULL;
}
return shm;
}
void shm_write(shm_t *shm, void *data)
{
void *shm_data;
if ((shm_data = shmat(shm->id, NULL, 0)) == (void *) -1)
{
perror("write");
return;
}
memcpy(shm_data, data, shm->size);
shmdt(shm_data);
}
void shm_read(void *data, shm_t *shm)
{
void *shm_data;
if ((shm_data = shmat(shm->id, NULL, 0)) == (void *) -1)
{
perror("read");
return;
}
memcpy(data, shm_data, shm->size);
shmdt(shm_data);
}
void shm_del(shm_t *shm)
{
shmctl(shm->id, IPC_RMID, 0);
free(shm);
}
int main()
{
int var = 1;
shm_t *shm = shm_new(sizeof var);
int pid;
if ((pid = fork()) == 0)
{ /* child */
var = 5;
shm_write(shm, &var);
printf("child: %d\n", var);
return 0;
}
/* Wait for child to return */
int status;
while (wait(&status) != pid);
/* */
shm_read(&var, shm);
/* Parent is updated by child */
printf("parent: %d\n", var);
shm_del(shm);
return 0;
}
Build with:
$ gcc shm.c -o shm && ./shm

sending array of integers via shared memory

I've written a producer and consumer code wherein a character sequence written to shared memory from producer.c is read from consumer.c
But the problem occured when I tried to send integer array from producer.c via shared memory and read from consumer.c
producer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main(){
const int SIZE = 4096;
const char *Obj = "Shm";
int shm_fd;
void *ptr;
shm_fd = shm_open(Obj, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, SIZE);
ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED)
{
printf("Map failed\n");
return -1;
}
fgets(ptr, SIZE, stdin);
printf("Producer: Writing the sequence to the shared-memory object is done! \n");
return 0;
}
consumer.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 4096;
const char *Obj = "Shm";
int shm_fd;
void *ptr;
shm_fd = shm_open(Obj, O_RDONLY, 0666);
if (shm_fd == -1)
{
printf("Shared memory failed\n");
exit(-1);
}
ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED)
{
printf("Map failed\n");
exit(-1);
}
printf("Consumer: The output sequence is: %d", (int *)ptr);
if (shm_unlink(Obj) == -1)
{
printf("Error removing the shared memory object %s\n", Obj);
exit(-1);
}
return 0;
}

Using semaphores with shared memory while running multiple processes

I am learning some simple producer/consumer examples involving semaphores, but having a hard time explaining to myself why I am getting a certain result (because I am a noobie to C).
When I run two concurrent processes of the following producer, both processes get hung up and never finish:
#include <stdio.h>
#include <sys/types.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#define BUFF_SIZE 20
typedef struct {
char buffer[BUFF_SIZE];
int nextIn;
int nextOut;
} shared_data;
shared_data *shm, *s;
char sem_name1[] = "mutex";
char sem_name2[] = "empty_slots";
char sem_name3[] = "full_slots";
sem_t *empty_slots;
sem_t *full_slots;
sem_t *mutex;
void Put(char item)
{
sem_wait(empty_slots);
sem_wait(mutex);
s->buffer[s->nextIn] = item;
s->nextIn = (s->nextIn + 1) % BUFF_SIZE;
sem_post(mutex);
printf("Producing %c ... with pid = %d\n", item, getpid());
sem_post(full_slots);
}
void Producer()
{
int i;
for(i = 0; i < 10; i++)
{
sleep(rand()%3);
Put((char)('A'+ i % 26));
}
}
void main()
{
//Create and initialize the semaphores
mutex=sem_open(sem_name1, O_CREAT,0644, 1);
full_slots=sem_open(sem_name3, O_CREAT,0644, 0);
empty_slots=sem_open(sem_name2, O_CREAT,0644, 10);
//Create a key for the segment
key_t key;
key = 1234;
//create the segment
int shmid;
if ((shmid = shmget(key, sizeof(shared_data), IPC_CREAT |0666)) <0)
{
perror("Shmget");
exit(1);
}
//attach to the segment
if ((shm = (shared_data *) shmat(shmid, NULL, 0))==(shared_data *) -1)
{
perror("Shmat");
exit(1);
}
s=shm;
s->nextIn = 0;
Producer();
//detach from the segment
shmdt((void *) shm);
}
The output from the first and second processes, respectively:
Can someone help me understand why this happens (i.e. why do these processes never finish)? Have I created a deadlock? Why or why not? I am completely stumped.
Thanks!

Writing barrier with shared memory in C

I need to write barrier for process synchronisation. I did and it was working until I put struct barrier in shared memory. My code is as follows:
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
void nanosleep2(long t)
{
struct timespec a;
a.tv_sec = 0;
a.tv_nsec = t;
nanosleep(&a, NULL);
}
struct barrier
{
int n; // number of processes
sem_t mutex;
int count;
sem_t bar;
};
void init(struct barrier * b, int n)
{
b->n = n;
b->count = 0;
sem_init(&b->mutex, 0, 1);
sem_init(&b->bar, 0, 0);
}
void destroy(struct barrier * b)
{
sem_destroy(&b->mutex);
sem_destroy(&b->bar);
}
void wait(struct barrier * b)
{
sem_wait(&b->mutex); // It seems that some processes never get acces to mutex, but isn't it impossible?
++(b->count);
printf("Horse is there!, %d/%d\n", b->count, b->n);
if (b->count == b->n)
{
printf("the barierr is open!\n");
sem_post(&b->bar);
}
sem_post(&b->mutex);
sem_wait(&b->bar);
sem_post(&b->bar);
}
struct barrier * barr_open(const char * name)
{
int fd = shm_open(name, O_RDWR | O_CREAT, 0666);
ftruncate(fd, sizeof(struct barrier));
struct barrier * res = mmap(NULL, sizeof(struct barrier), PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
close(fd);
return res;
}
void barr_close(struct barrier * barr, const char * name) // if name is not NULL, it also unlinks
{
munmap(barr, sizeof(struct barrier));
if (name != NULL)
shm_unlink(name);
}
const int N = 5; // number of horses
void * horse(void * _)
{
struct barrier * barr = barr_open("/barieraa");
nanosleep2((rand()%200)+10);
wait(barr);
barr_close(barr, NULL);
return NULL;
}
int main()
{
srand(time(NULL));
struct barrier * barr = barr_open("/barieraa");
init(barr, N);
sleep(1);
int i;
for (i = 0; i < N; i++)
{
pthread_t t;
pthread_create(&t, NULL, horse, NULL);
pthread_detach(t);
nanosleep2(rand()%200);
}
sleep(1);
destroy(barr);
barr_close(barr, "/barieraa");
return 0;
}
So, the first printf in wait() only three or four horses are able to reach. Probably something grabs mutex and doesn't return, but is it possible? Why barrier itself works, shared memory itself works, but they both together don't want?

how to write integer var to file using write() function in c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
void *func(void *ptr);
int file;
int main()
{
pthread_t thread1, thread2;
int iret1, iret2;
int p;
p=1;
file=open("file1.txt", O_CREAT | O_TRUNC | O_RDWR , 0666);
iret1 = pthread_create(&thread1, NULL, func, (void *)&p);
pthread_join(thread1, NULL);
close(file);
exit(0);
}
void *func(void *ptr)
{
int *num;
int i;
num = (int *)ptr;
printf("%d ", *num);
for (i=0; i<10; i++)
{
printf("%d", *num);
write(file, *num, sizeof(*num));
}
}
How to write integer var to file using write() function in c?
This is my code. The problem is in the func(). If I use chars or const int it's working fine.
First, read the man page of write(). It writes bytes, not element types.
So, what you are trying to achieve, cannot be accomplished directly with write(). you need to use snprintf() to convert the int to char string, which you can use with write(). Please check the following code.
1. Define a char array, print the value of the int pointer to that array using snprintf().
2. Use the char array as the argument of write(). It'll work.
NOTE: It's always a best practice to add some error check to the system calls and library calls. It provides many useful information in the case they fail.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
void *func(void *ptr);
int file;
int main()
{
pthread_t thread1, thread2;
int iret1, iret2;
int p;
p=1;
file=open("file1.txt", O_CREAT | O_TRUNC | O_RDWR , 0666);
iret1 = pthread_create(&thread1, NULL, func, (void *)&p);
pthread_join(thread1, NULL);
close(file);
exit(0);
}
void *func(void *ptr)
{
int *num;
int i, ret = -1;
num = (int *)ptr;
char buf[4] = {0}; //to use with write()
printf("%d\n", *num);
for (i=0; i<10; i++)
{
printf("%d", *num);
memset(buf, 0, sizeof (buf));
snprintf(buf, sizeof *num, "%d", *num); //print to buffer
ret = write(file, buf, strlen(buf)); //write the buf to file
if (ret < 0) //check for erroneous condition
printf("ret is %d, errno %d\n", ret, errno);
}
}
write(fd, &var, sizeof(i)); is a short fix for this question.

Resources