I would like to do multi-process programming where I need to share data (reader/writer case).
My idea is to use shared memory to track read/write index.
And the index indicates the shared file index.
For example, if write index = 2, it means writer is writing shared file named
"temp_2.data". if read index = 1, it means reader is reading shared file named "temp_1.data".
My problem is:
Do I need the synchronization mechanism when, ex: accessing rptr below? or shm_open itself promises the synchronization? If so, how it makes the synchronization?
The hybrid design of shared memory and shared file makes sense? Or if there is any better way?
Thanks~
#include <unistd.h>
#include <sys/mman.h>
...
#define MAX_LEN 10000
struct region { /* Defines "structure" of shared memory */
int len;
char buf[MAX_LEN];
};
struct region *rptr;
int fd;
/* Create shared memory object and set its size */
fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
/* Handle error */;
if (ftruncate(fd, sizeof(struct region)) == -1)
/* Handle error */;
/* Map shared memory object */
rptr = mmap(NULL, sizeof(struct region),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (rptr == MAP_FAILED)
/* Handle error */;
/* Now we can refer to mapped region using fields of rptr;
for example, rptr->len */
...
Related
I have a structure A of the form described below. My goal is to create the structure in one process and share it across to a different process. A->buffer depends upon user_size and value provided and hence I cannot have a pre-allocated buffer. Knowing that sharing pointers with shared memory is hard across processes since pointer value in one process will no longer be valid in the other process, I tried the following approach.
I wanted to allocate the buffer from shared memory, from the writing process so that other processes can map to the same shared memory and obtain a valid pointer address to the shared memory.
Conceptually, calling mmap on the same shared memory fd descriptor should point to the same location in shared memory, however on the reading process, I'm able to get a valid pointer and valid another_value.
Can someone clarify this? Parts of the code below.
struct A {
int another_variable;
void *buffer;
}
/* 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;
/* 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);
a_data = mmap(NULL, sizeof(*A), PROT_READ | PROT_WRITE, MAP_SHARED,
shm_fd, 0);
if (a_data == MAP_FAILED) {
printf("ERROR: mmap failed for a_data\n");
exit(EXIT_FAILURE);
}
a_data->buffer = mmap(NULL, user_size, PROT_WRITE,
MAP_SHARED , shm_fd, 0);
if (a_data->buffer == MAP_FAILED) {
printf("ERROR: mmap failed for a_data buffer\n");
exit(EXIT_FAILURE);
}
memcpy(a_data->buffer, "test", strlen("test"));
So I have an assignment to create a library of functions that can create a posix shared memory table, add a record, delete a record and close the table. For the close_table function my prof wants it to only disconnect the current process calling close_table, so if there are two or more processes connect to the shared memory, only the one that called close_table will be disconnected. Looking at the different functions for working with posix shared memory it seems shm_unlink is the only thing that does something like that, except is deletes the shared memory object itself. is there a function that only disconnects only the process calling it?
/* Close connection to the given table. This should only disconnect
* the current process from the table.
*/
void close_table(table_t *tbl);
From the POSIX shm_open() documentation, the creation of the shared memory region is:
fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
/* Handle error */;
if (ftruncate(fd, sizeof(struct region)) == -1)
/* Handle error */;
/* Map shared memory object */
rptr = mmap(NULL, sizeof(struct region),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
To remove the mapping:
munmap( rptr, sizeof(struct region));
That's all that's needed.
You should have probably closed the file descriptor after calling mmap() as it's no longer needed or even very useful at that point.
I am using shared memory for communication between two different process. I am creating shared memory of 16 MB size. I am trying to attach two different parts of the shared memory. One for writing and other for reading. Even though it maps to different memory address but when one is modified other also gets changed. I must be doing something wrong. Below is the code snippet where I am attaching to multiple shared memory location.
void createCommPool ()
{
CommSet set1;
int shmid1;
int fd1;
int r;
void * ptr;
void * ptr_res;
umask (0);
fd1 = open(SHARED_MEMORY0, O_CREAT | O_TRUNC | O_RDWR, 0777);
if (fd1 == -1)
error_and_die("open");
r = ftruncate(fd1, region_size);
if (r != 0)
error_and_die("ftruncate");
ptr = mmap(0, sizeof(struct operation_st), PROT_READ | PROT_WRITE,
,MAP_SHARED,fd1,sizeof(struct operation_st));
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd1);
set1.shm_addr = ptr;
fd1 = open(SHARED_MEMORY0, O_RDWR, 0777);
if (fd1 == -1)
error_and_die("open");
fprintf(stderr,"The value of the file descriptor:%d\n",fd1);
if (lseek(fd1,sizeof(struct operation_st),SEEK_SET)<0)
{
fprintf(stderr,"could not perform lseek\n");
perror("lseek");
}
ptr_res = mmap(0,sizeof(struct operation_st), PROT_READ| PROT_WRITE,
MAP_SHARED,fd1,0);
if (ptr_res == MAP_FAILED)
error_and_die("mmap2");
close(fd1);
set1.shm_addr_res = ptr_res;
}
For data in shared memory, avoid the influence of bytes alignment with pack:
#pragma pack(1)
your shared memory code
#pragma unpack
lseek does not have any effect on the mapping of the shared memory. The offset parameter should be used in order to map to the different part of the shared memory. The offset should be in multiples of page size.
I have a process that dived itself with fork. I need to create a region of memory (a matrix) for the result of the computation of each process. How can I do this? Everything I tried or I can use but it's not shared between processes or I can't use (not sure if shared or not). Someone knows what I can use? It can be something simple and without any security. The simpler the better.
I tried shmget but it's not sharing and I couldn't get how to use mmap to allocate or use it correctly. I tried other estranges things, but nothing. Any tips?
Some tries:
segment_id = shmget(IPC_PRIVATE, (sizeof(int) * linhas_mat1 * colunas_mat2) , S_IRUSR|S_IWUSR);
matriz_result = (int **) shmat(segment_id, NULL, 0);
Forks after that. Each process can use the matriz_result normally as a matrix, but the memory is not shared. Each one has one like a local variable.
segment_id = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
matriz_result = mmap(NULL, (sizeof(int) * linhas_mat1 * colunas_mat2), PROT_READ | PROT_WRITE, MAP_SHARED, segment_id, 0);
Tried this with mmap, but I don't know if it's right. I'm not good with such low level programming and I couldn't find any good example on how to use it correctly.
declarations:
int segment_id is;
int **matriz_result;
int createMemShare(){
//File descriptor declaration:
int fd;
//We want to open the file with readwrite,create it, and empty it if it exists
//We want the user to have permission to read and write from it
fd = open(MEMSHARENAME, O_RDWR| O_CREAT | O_TRUNC, S_IRUSR| S_IWUSR );
if(fd <= 0){
puts("Failed in creating memory share .");
return -1;
}
//Move the file pointer and write an empty byte, this forces the file to
//be of the size we want it to be.
if (lseek(fd, MEMSHARESIZE - 1, SEEK_SET) == -1) {
puts("Failed to expand the memory share to the correct size.");
return -1;
}
//Write out 1 byte as said in previous comment
write(fd, "", 1);
//Memory share is now set to use, send it back.
return fd;
}
//Later on...
int memShareFD = mmap(NULL, MEMSHARESIZE, PROT_READ, MAP_SHARED, fd, 0);
//And to sync up data between the processes using it:
//The 0 will invalidate all memory so everything will be checked
msync(memshareFD,0,MS_SYNC|MS_INVALIDATE);
you can try the above function to create a shared memory space. Essentially all you need to do is treat it like any other file once you've made it. The code example on the man page is pretty complete and worth a look into: check it out here
Edit:
You'd probably be better off using shm_open as Jens Gustedt suggested in the comments. It's simple to use and simpler than making the file yourself with the function I've written above.
I have an issue attempting to access shared memory using mmap for complex types.
So I allocate my memory as so in my parent process:
/* Create mmap file */
fid = open(TMP_FILE_NAME, O_RDWR | O_CREAT | O_EXCL, (mode_t) 0755);
if (fid < 0)
{
printf("Bad Open of mmap file <%s>\n", TMP_FILE_NAME);
die(-1);
}
/* Make mmap file Buffer Size */
status = ftruncate(fid, INPUT_BUFFER_SIZE);
if (status)
{
printf("Failed to ftruncate the file <%s>, status = %d\n", TMP_FILE_NAME, status);
die(-1);
}
/* Initialize Shared Memory */
mmap_ptr = mmap((caddr_t) 0,
INPUT_BUFFER_SIZE, // Default Buffer Size
PROT_WRITE | PROT_READ, // R/W Permissions
MAP_SHARED, // No file backing
fid,
(off_t) 0);
if (mmap_ptr == MAP_FAILED)
{
printf("Failed to perform mmap, Exiting\n");
die(-1);
}
Now the Struct that I'm passing in memory to my child process is as follows:
/* Data structue for IPC */
typedef struct {
int current_active_id;
int consume_remaining;
Queue buffer;
} input_buffer;
where Queue is a data structure class from the following:
http://www.idevelopment.info/data/Programming/data_structures/c/Queue/Queue.shtml
In my child process it's okay when I do this, it returns the correct value:
printf("Got here... Shared Mem: %d\n", input_queue->consume_remaining);
but when I do something like:
IsEmpty(input_queue->buffer)
it crashes and in the code of the Queue it's only doing this:
return Q->Size == 0;
Any help would be appreciated, thanks!!
Queue is a pointer to struct QueueRecord, and should be allocated as such, presumably using the same shared memory segment. note that this should also be mapped at the same address in both parent and child, or you will not be able to dereference it.
The structure you are putting in the map contains pointers. The pointers are all relative to the address space of the process that created them.
If the other process doesn't mmap at the same address, or if it does but the allocations made for the queue aren't taken from inside that buffer, the pointers will be invalid in the other process.