I have two small programs. 'Server' creates some shared memory with shm_open and writes in a loop to the shared memory. 'Client' reads from the shared memory and displays the current value. 'Client' does not see the updates from 'Server' unless 'Server' makes a syscall like sleep or printf.
The below code only works with sleep(1) uncommented in Server.c:
Server.c
#include <sys/mman.h>
#include <fcntl.h>
int main (int argc, char *argv[]){
int fd = shm_open("/SHM_TEST", O_RDWR | O_CREAT, S_IRWXU);
ftruncate(fd, 4096);
unsigned char *ptr = mmap(0,4096,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,fd,0);
while(1){
for(unsigned short int i=0;i<256;i++){
*ptr = i;
//sleep(1);
}
}
}
Client.c
#include <sys/mman.h>
#include <fcntl.h>
int main (int argc, char *argv[]){
int fd = shm_open("/SHM_TEST", O_RDWR, S_IRWXU);
unsigned char *ptr = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
int i = 0;
while(1){
printf("%d--%d\n", *ptr, i);
i++;
}
}
I assume there is some caching going on or the "shared memory" isn't really sharing the same memory space. Is there a way to share memory without having to make any syscalls once it's setup? To have the two programs share the same physical memory? I don't care about race conditions, etc.
Related
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);
I am trying to synchronize two proccesses to read and write into shared memory. Here is a_process.c:
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#define SHM_PATH "/instant_messaging"
#define SHM_SIZE 50
#define SEM_PATH "/sem_instant_messaging"
char *sendbuff;
int main()
{
//sahred memory setting
//shm_unlink(SHM_PATH);
int shmfd;
shmfd = shm_open(SHM_PATH, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
int shm_size = SHM_SIZE;
ftruncate(shmfd, shm_size);
sendbuff = (char*) mmap(NULL, shm_size, PROT_READ | PROT_WRITE,
MAP_SHARED, shmfd, 0);
if (sendbuff == NULL) {
perror("In mmap()");
exit(1);
}
//semaphore setting
sem_unlink(SEM_PATH);
sem_t * sem1;
sem1 = sem_open(SEM_PATH, O_CREAT, S_IRUSR | S_IWUSR, 1);
printf("before while\n");
//setmemshr();
//setsem();
while (1) {
int status = sem_wait(sem1);
if (status != 0)
{
perror("in sem_wait");
}
printf("after wait\n");
printf("%s\n",sendbuff);
scanf("%s",sendbuff);
sem_post(sem1);
//sleep(3);
}
}
and here is b_process.c:
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#define SHM_PATH "/instant_messaging"
#define SHM_SIZE 50
#define SEM_PATH "/sem_instant_messaging" //dddddddddd
char *sendbuff;
int main()
{
//sahred memory setting
//shm_unlink(SHM_PATH);
int shmfd;
shmfd = shm_open(SHM_PATH, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
int shm_size = SHM_SIZE;
ftruncate(shmfd,shm_size);
sendbuff = (char*) mmap(NULL, shm_size, PROT_READ | PROT_WRITE,
MAP_SHARED, shmfd, 0);
if (sendbuff == NULL) {
perror("In mmap()");
exit(1);
}
//semaphore setting
sem_unlink(SEM_PATH);
sem_t *sem1;
sem1 = sem_open(SEM_PATH, O_CREAT, S_IRUSR | S_IWUSR, 1);
while (1) {
printf("before wait %d\n", *sem1);
int status = sem_wait(sem1);
if (status != 0)
{
perror("in sem_wait");
}
printf("after wait %d\n", *sem1);
printf("%s", sendbuff);
scanf("%s", sendbuff);
sem_post(sem1);
}
}
I have spent a lot of time debugging this and reading man pages, but it seems that although shared memory works and semaphore post and wait work within each process's address space, the two processes do not either one affect the data the other sees in the shared memory region.
Does anyone see what I am missing?
There are a few things in your code that are suspicious, but one combination of things stands out as definitely wrong: both processes perform a sem_unlink() followed immediately by a sem_open() on the semaphore path. This can have the effect of the two procs using the same semaphore only if you are absurdly lucky, such that both sem_unlink()s are performed before either sem_open() is performed. Otherwise, whichever process goes second will unlink the semaphore created by the first, and instead create and use its own. Both processes will proceed, each using its own, independent semaphore.
I also find it a bit suspicious that both processes ftruncate() the shared memory region, and especially that they do so before synchronizing (or would do if the procs were effectively synchronizing at all). I think you should make one process responsible for setting up the shared memory segment; the other needs only open and map it. Correct your semaphore initialization, and use the semaphore to ensure that the shared memory is sized before either program proceeds to using it.
I have the following main.c:
#include <unistd.h> //has thread calls for fork()
#include <stdio.h>
struct globalInfo{
int x;
};
int do this()
{
info.x++;
printf("%d\n",info.x);
return 0;
}
int main{
struct globalInfo info = { .x = 2};
for(int i = 0 ; i < 5 ; i++)
{
if(fork() = 0)
{
dothis();
}
}
}
This isn't my exact code, but my question is more easily demonstrated here.
Now the output for the above function is:
3
3
3
3
3
What I want is:
3
4
5
6
7
How do share this struct between threads? It seems like every thread is just creating its own copy of the struct and manipulating its own copy. I've tried to pass a pointer to the info struct as a parameter to dothis(), but that doesn't fix it either. I've also tried placing the info initialization out of the main; that didn't work either..
Help would be greatly appreciated.
fork() doesnot create a thread it creates processes, processess will have different address spaces altogether hence data wil not be shared even if it is global data.
in case you are thinking of threads use pthreads
incase you are looking for processes you need to use IPC mechanisms
Use any IPC to share data b/w processes. In threads the data can be shared by following methods:
return value of thread passed to pthread_exit and catch in pthread_join
shared/global resource of process accessed by synchronizing methods
As people have already noted you are creating processes not threads. Sharing data among processes is harder. Every process has its own memory address space which means that they may share same code, but their data is private.
There are several techniques if you want to have shared data among processes. One of them is shared memory with memory map
#include <unistd.h> //has thread calls for fork()
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
struct globalInfo{
int x;
};
char *shm = "/asd8"; // change this before every run to avoid error 22
int dothis()
{
// sleep(1); // helps to simulate race condition
int len = sizeof(struct globalInfo);
int fd = shm_open(shm, O_RDWR, 0);
void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED){
perror(""); // error handling
}
struct globalInfo *info = (struct globalInfo *)addr;
info->x++;
printf("%d %d\n", info->x, getpid());
return 0;
}
int main(){
struct globalInfo info = { .x = 2};
int len = sizeof(struct globalInfo);
int fd = shm_open(shm, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
perror(""); // error handling
if(ftruncate(fd, len) == -1){
printf("%d\n", errno); // osx produces error 22 don't know why
perror("");
}
void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
memcpy(addr, &info, len);
for(int i = 0 ; i < 5 ; i++)
{
if(fork() == 0)
{
dothis();
break;
}
}
}
sample output
3 30588
4 30589
6 30590
6 30591
7 30592
Also it would be great if you read chapters from The Linux Programming Interface: A Linux and UNIX System Programming Handbook
24 Process Creation
49 Memory Mapping
53 POSIX Semaphores (you have to solve synchronisation problem after the data is shared)
54 POSIX Shared Memory
I was trying to figure out shared memory and tried to write a simple program involving a consumer and a producer. I didnt make it to the consumer part and found this weird little problem: The parent will return at the *spool=3; with no rhyme or reason on why. Nothing on dmesg.
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define PRODUCER_ERROR(msg) \
do {perror("Producer Error: " msg "\n"); exit(1); }while(0)
#define SHM_NAME "/my_sharedmem"
void producer();
int main(int argc, char *argv[])
{
pid_t pID = fork();
if (pID == 0) {
// Code only executed by child process
printf ("Son here\n");
return 0;
} else if (pID < 0) {
perror("Unable to fork\n");
exit(1);
} else {
// Code only executed by parent process
printf ("Parent here\n");
producer();
return 0;
}
return 0;
}
void producer()
{
int fd, d;
unsigned* spool;
printf("<<Producer>> started\n");
fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO ); // FIXED
printf ("<<Producer>> memory file opened\n");
spool = mmap(NULL, sizeof(unsigned), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0);
printf ("<<Producer>> mmaped to %p\n\tGonna write.\n", spool);
perror(NULL);
*spool = 3;
// msync(spool, sizeof(unsigned), MS_SYNC | MS_INVALIDATE);
printf("<<Producer>> ended\n");
}
EDIT: fixed shm_open mode argument
The object you get with shm_open is zero size. You need to allocate some space for it. mmap will allow you to map things beyond their size (both shm objects and files), but you'll crash when you access that memory.
Something like this after shm_open is what you want to do:
ftruncate(fd, <the size you want>);
You can do it after mmap too, if that floats your boat.
You have the mode argument to shm_open wrong. This is supposed to be a mode specification as for open. Probably your version here by conincidence forbids writing to the address, so the process then crashes when you try to write to it.
BTW: you should always check the return of library calls such as shm_open and mmap.
Edit: As I also observed in a comment below, you are also missing to scale the segment to an appropriate size with ftruncate.
I create a shared memory in program A with the following codes:
shm = shm_open("/mfs_hash_pool_container", O_CREAT|O_RDWR, 0666);
size = sizeof(struct mfs_hash_pool_container);
ftruncate(shm, size);
mfs_hash_pool_stat_p = (struct mfs_hash_pool_container *)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm, 0);
I use that to store a hash table.
The other program B, will receives the addr (mfs_hash_pool_stat_p+offset) send from program A, but I can not write it in B.
Does this means I must also open this shared memory in B? Is there any other way to solve that? Because I create this memory automatically.
Thanks you guys.
You can't just use that address in the other program. B has to:
Obtain the file descriptor: shm_open("/mfs_hash_pool_container", O_RDWR, 0)
Map memory for the file descriptor: mmap just like A does
Notes:
You need to check the return value of mmap (it could return MAP_FAILED)
You need not cast the return value of mmap
Separate processes do not share memory, so the address being passed to B from A will not point to the shared memory segment. Each process must call shm_open() and mmap() the segment individually.
If you have information about the segment that every process needs to be aware of, pack it at the beginning of the segment in an order that each process is aware of.
I am not sure about how your program A and program B are related, but if you manage to spawn 'B' from 'A', using fork() + execve() combination, then you need not worry about passing the memory pointer as both processes will have the same copy.
For your reference I am pasting a nice code example present at IBM developerworks here-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
void error_and_die(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
int r;
const char *memname = "sample";
const size_t region_size = sysconf(_SC_PAGE_SIZE);
int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666);
if (fd == -1)
error_and_die("shm_open");
r = ftruncate(fd, region_size);
if (r != 0)
error_and_die("ftruncate");
void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd);
pid_t pid = fork();
if (pid == 0)
{
u_long *d = (u_long *)ptr;
*d = 0xdbeebee;
exit(0);
}
else
{
int status;
waitpid(pid, &status, 0);
printf("child wrote %#lx\n", *(u_long *)ptr);
}
r = munmap(ptr, region_size);
if (r != 0)
error_and_die("munmap");
r = shm_unlink(memname);
if (r != 0)
error_and_die("shm_unlink");
return 0;
}
Read the full article in the above link to gain a better understanding of shared memory!
Process do not share memory by default. If you want this 2 processes to communicate or share memory, you'll have to make that happen. Check this question.
Another solution is to use threads, which share code and memory alike.