0
#include <fcntl.h>
#include <semaphore.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/stat.h> /* For mode constants */
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <thread>

using namespace std;



const char* shm_path = "conn_close_test";

char buf[] = "666";

int main() {
  sem_t* sem_child;
  sem_t* sem_parent;

  // int flag = O_CREAT | O_EXCL | O_RDWR;
  int flag = O_CREAT | O_RDWR;
  // create share memory object
  int fd = shm_open(shm_path, flag, S_IRUSR | S_IWUSR);
  if (fd == -1) {
    std::cout << "create failed  for reason: " << strerror(errno) << std::endl;
    return -1;
  }

 int page_size = 4096;

  if (ftruncate(fd, page_size  * 2) == -1) {
    std::cout << "ftruncate failed : " << strerror(errno) << std::endl;
    return -1;
  }

  // create semphore
  sem_child = (sem_t*)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE,
                           MAP_SHARED, fd, 0);
  if ((__int64_t)(sem_child) == -1) {
    std::cout << "mmap sem child  failed for reason:" << strerror(errno)
              << std::endl;
  }

  sem_parent = (sem_t*)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE,
                            MAP_SHARED, fd, page_size);
  if ((__int64_t)(sem_parent) == -1) {
    std::cout << "mmap sem parent failed for reason:" << strerror(errno)
              << std::endl;
  }

  int ret = sem_init(sem_child, 1, 0);
  if (ret == -1) {
    std::cout << "sem_child sem_init failed for: " << strerror(errno)
              << std::endl;
    return -1;
  }
  ret = sem_init(sem_parent, 1, 0);
  if (ret == -1) {
    std::cout << "sem_parent sem_init failed for: " << strerror(errno)
              << std::endl;
    return -1;
  }

  // fork
  pid_t pid = fork();
  if (pid == 0) {
    // child process read buf first  then post a semophore to wakeup parent process
    std::cout << "children first read\n";
    std::cout << "buf: " << buf << std::endl;
    std::cout << "sem_child post to wake up parent process" << std::endl;
    sem_post(sem_child);

    std::cout << "child process waiting for  sem_parent" << std::endl;
    sem_wait(sem_parent);
    std::cout << "children second read\n";
    std::cout << "buf: " << buf << std::endl;
  } else if(pid > 0 ){

    std::cout << "parent process waiting for sem_child\n";
    sem_wait(sem_child);
    std::cout << "parent  first read\n";
    std::cout << "buf: " << buf << std::endl;

    buf[0] = buf[1] = buf[2] = '7';
    std::cout<<"modify buf "<<std::endl;
    std::cout << "buf: " << buf << std::endl;

    std::cout<<"sem_parent post to wake up child process"<<std::endl;
    sem_post(sem_parent);
  }
  return 0;
}

compile it and run

chenbh@ubuntu:~/projects/conn_close_test$ g++ sem_test.cpp -lrt -lpthread -O0 -g 
chenbh@ubuntu:~/projects/conn_close_test$ ./a.out 
parent process waiting for sem_child
children first read
buf: 666
sem_child post to wake up parent process
child process waiting for  sem_parent
parent  first read
buf: 666
modify buf 
buf: 777
sem_parent post to wake up child process
children second read
buf: 666

here is my program, I make a buffer in parent process, then fork a child process to read the buffer and the parent process start to wait for a semaphore posted by child process, parent process will change the content of buffer after receive semaphore and notify child process to read it again, but my program shows child process read the old content of buffer, according to fork()'s cow, child process doesn't change the content of buffer then it should read the newest content from it, isn't it?

Lundin
  • 195,001
  • 40
  • 254
  • 396
woder
  • 647
  • 5
  • 12
  • `fork` creates a new process with a **copy** of the parent's address space. Changing the `buf` in the parent process does not change the `buf` in the child process. – kaylum Jan 20 '21 at 10:28
  • `if ((__int64_t)(sem_child) == -1)`?!?!? Why are you incorrectly trying to reinvent `MAP_FAILED`? – Andrew Henle Jan 20 '21 at 10:33
  • 1
    Does this answer your question? [Using shared memory with fork()](https://stackoverflow.com/questions/6449343/using-shared-memory-with-fork) – user202729 Jan 20 '21 at 10:39
  • I think there's a misunderstanding how this works, as kaylum already mentioned. `cow` stands for `copy-on-write`. – domen Jan 20 '21 at 13:16
  • buf [], should be inside the shared memory. Now it is just a global variable. The address space of parent and child are different. So buf is different in parent and child processes. – kjohri Jan 20 '21 at 14:40
  • @Andrew Henle thanks, use `MAP_FAILED` is better – woder Jan 21 '21 at 06:24
  • @user202729 no, there are different – woder Jan 21 '21 at 06:25

1 Answers1

0

thanks for comments, I am now understanding copy-on-write;

when parent process execute system call as fork or exec, prosess's memory pages will be set to read-only, these memory pages will be copied to parent/child's process space while parent/child process tries to write these memory pages.

I was wrong to think cow is child process copy memory pages from parent process firstly.

woder
  • 647
  • 5
  • 12