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;
}
Related
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
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.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 500;
const char *name = "name";
int fd;
char *ptr = NULL;
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) {
fd = shm_open(name,O_CREAT | O_RDWR,0666);
ftruncate(fd, SIZE);
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sprintf(ptr, "%s", "Hello, World!\n");
return 0;
}
else {
wait(NULL);
fd = shm_open(name, O_RDONLY, 0666);
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("%s\n", (char *)ptr);
}
return 0;
}
I am basically looking to create some shared memory in the child process and access it from the parent.
In the child process, the mmap works fine. When I print using the pointer returned by mmap it does in fact print Hello, World!, but the same print gives a seg fault from the parent.
In the parent (pid != 0) you opened the object O_RDONLY, but mmapped it with PROT_WRITE, MAP_SHARED. Remove the | PROT_WRITE and you are fine.
You might want to check the return values for errors the odd time.
The crash is due to this excerpt from man:
O_RDONLY Open the object for read access. A shared memory object
opened in this way can be mmap(2)ed only for read
(PROT_READ) access.
You've attempted to:
fd = shm_open(name, O_RDONLY, 0666);
// ^^^^^^^^
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// ^^^^^^^^^^^^ incorrect!
Another remark: your name should follow the man recommendation for portability:
For portable use, a shared memory object should be identified by a name
of the form /somename; that is, a null-terminated string of up to
NAME_MAX (i.e., 255) characters consisting of an initial slash,
followed by one or more characters, none of which are slashes.
Lastly, you have some unnecessary (char *) casts and always error check your return values.
Within a Ubuntu virtal machine, I have created two c programs called "server" and "client". When I run server with an input (some integer) and then run client afterwards, client will output the integer that I gave to server. This is working with shared memory. My problem is, after client receives the info, it sets a variable to "CONSUMED", and server has a loop that waits for that to happen, but it never seems to work correctly. This all works if I remove the loop altogether, but I need it in there to be able to ensure that client receives the integer and I don't just continue without it happening.
Here is my code for server.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include "shm.h"
int main(int argc, char* argv[]){
int retVal = 0;
ShmData *addr;
if(argc != 2){
printf("please enter 1 argument.\n");
return 0;
}
int fd = shm_open("shm.h", O_CREAT | O_RDWR , 0666);
if(fd == -1){
printf("!!!error with shm_open.\n");
}
if(ftruncate(fd, sizeof(ShmData)) == -1){
printf("!!!error with ftruncate.\n");
}
addr = mmap(0, sizeof(ShmData), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(addr == MAP_FAILED){
printf("!!!error with mmap.\n");
}
addr->status = INVALID;
addr->data = atoi(argv[1]);
addr->status = VALID;
printf("[Server]: Server data Valid... waiting for client\n");
while(addr->status != CONSUMED){
sleep(1); //THIS LOOP NEVER EXITS
}
printf("[Server]: Server Data consumed!\n");
munmap(addr, 0);
if(close(fd) == -1){
printf("!!!error with close.\n");
}
shm_unlink("smh.h");
printf("[Server]: Server exiting...\n\n\n");
return(retVal);
}
Here is my code for client.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include "shm.h"
int main(int argc, char* argv[]){
int retVal = 0;
int fd = shm_open("shm.h", O_CREAT | O_RDWR , 0666);
if(fd == -1){
printf("!!!error with shm_open.\n");
}
ShmData *addr;
addr = mmap(0, sizeof(ShmData), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("[Client]: Waiting for valid data ...\n");
while(addr->status != VALID){
sleep(1);
}
printf("[Client]: Received %d\n", addr->data);
addr->status = CONSUMED;
munmap(addr, 0);
printf("[Client]: Client exiting...\n");
return(retVal);
}
And here is the shm.h file:
enum StatusEnum{INVALID, VALID, CONSUMED};
typedef struct{
enum StatusEnum status;
int data;
}ShmData;
I've been banging my head against the computer screen for a long time but I still don't see anything wrong with my code. How can I get this loop to succeed and exit?
How can I use mmap to map a character device file to my application? I've tried the following code which fails because the size of the file is zero (sb.st_size == 0). Is there another way or is this impossible all together? Thanks.
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int init_module(void *module_image, unsigned long len,
const char *param_values);
int main() {
int res = 0;
void *buf = 0;
struct stat sb;
int rc = 0;
int fd = open("/dev/nvidia0", O_RDWR);
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
res = fstat(fd, &sb);
if (res == -1) {
perror("fstat");
exit(EXIT_FAILURE);
}
buf = mmap(0, sb.st_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0);
if (buf == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
munmap(buf, sb.st_size);
close(fd);
return EXIT_SUCCESS;
}