The goal of this code is to create a shared memory space and write n's value to it in the child then print all the numbers generated in from the parent process. But this presently just prints out memory addresses like 16481443B4 which change every time I run the program. I am not sure if I am writing to the shared memory incorrectly or reading from the shared memory incorrectly. Possibly both.
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/mman.h>
int main(int argc, char** argv){
//shared memory file descriptor
int shm_fd;
//pointer to shared memory obj
void *ptr;
//name of shared obj space
const char* name = "COLLATZ";
//size of the space
const int SIZE = 4096;
//create a shared memory obj
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
//config size
ftruncate(shm_fd, SIZE);
//memory map the shared memory obj
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
int n = atoi(argv[1]);
pid_t id = fork();
if(id == 0) {
while(n>1) {
sprintf(ptr, "%d",n);
ptr += sizeof(n);
if (n % 2 == 0) {
n = n/2;
} else {
n = 3 * n + 1;
}
}
sprintf(ptr,"%d",n);
ptr += sizeof(n);
} else {
wait(NULL);
printf("%d\n",(int*)ptr);
}
//Umap the obj
munmap(ptr, SIZE);
//close shared memory space
close(shm_fd);
return 0;
}
Listen to your compiler!
$ gcc main.c -lrt
main.c: In function 'main':
main.c:51:9: warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *' [-Wformat=]
printf("%d\n",(int*)ptr);
^
Assuming you want to print the integer pointed to by ptr, it should be:
printf("%d\n",*((int*)ptr));
Related
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;
}
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.
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);
#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.
I'm trying to pass some values between a parent and 10 child processes with shared memory and active wait.
Some values in the struct are pointers to allocate outside dynamic memory
The error is showing when i'm trying to write a number in a string to pass a path file with numbers, but I can't since the memory is not there, I can only do it without a number.
typedef struct {
char *path[10];
char *word[10];
int number_ocurrency[10];
int flag[10];
} shared_data_type;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
int fd;
int data_size = sizeof(shared_data_type),i;
pid_t pid;
shared_data_type *shared_data;
if((fd = shm_open("/ex06_searchWord", O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR))==-1)
{
perror("Error at shared memory allocation!\n");
return 0;
}
ftruncate (fd, data_size);
shared_data = (shared_data_type *)mmap(NULL,data_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
for(i=0; i<10;i++){
shared_data->flag[i]=0;
pid=fork();
if (pid == -1)
{
printf("Error at fork!\n");
return -1;
}
if (pid == 0) { /* reader */
while(!shared_data->flag[i]);
FILE *file;
file = fopen(shared_data->path[i], "r");
if (file == NULL)
{
printf("Could not open/find the specified file.\n");
return -1;
}
int size = 0;
char readChar=NULL;
char *msg = NULL;
while((readChar = fgetc(file)) != EOF) {
msg = (char *) realloc(msg, size+1);
*(msg + size) = readChar;
size++;
}
*(msg + size) = '\0';
int count = 0;
while(msg = strstr(msg, shared_data->word[i]))
{
count++;
msg++;
}
shared_data->number_ocurrency[i]=count;
exit(0);
}
if(pid>0){
shared_data->word[i]="SCOMP";
char path[16]="files/file1.txt";
shared_data->path[i]=malloc(sizeof(path)+1);
sprintf(shared_data->path[i],"files/file%d.txt",i);
//shared_data->path[i]= "files/file.txt";
shared_data->number_ocurrency[i]=0;
shared_data->flag[i]=1;
}
}
for(i=0; i<10;i++){
wait(NULL);
}
for(i=0; i<10;i++){
printf("The word %s in the son %d appeared: %d times\n",shared_data->word[i],i,shared_data->number_ocurrency[i]);
}
if (munmap(shared_data, data_size) == -1)
{
perror("Error at unmap!\n");
return 0;
}
if(shm_unlink("/ex06_searchWord")==-1){
perror("Error at unlink!\n");
return 0;
}
return 0;
}
When you share bytes between processes, you need to make sure those bytes contain something that is meaningful and understandable to all the processes that are going to use it. Putting pointers to memory that isn't shared in shared memory makes no sense. And unless all the processes can be guaranteed to map the shared memory at the same address, even putting absolute pointers to shared memory in shared memory makes no sense.
You can divide the shared memory into "slots" if you want and get the effect of having pointers in shared memory by placing the slot number in shared memory. The slot number will have to be translated to and from an absolute address in each process, taking into account the base address of the mapping.