【问题标题】:why `fork()` does't show cow in my test program?为什么`fork()`在我的测试程序中没有显示cow?
【发布时间】:2026-01-31 16:00:01
【问题描述】:
#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;
}

编译并运行

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

这是我的程序,我在父进程中创建一个缓冲区,然后派生一个子进程来读取缓冲区,并且父进程开始等待子进程发布的信号量,父进程将在接收后更改缓冲区的内容信号量并通知子进程再次读取它,但我的程序显示子进程读取缓冲区的旧内容,根据fork()cow,子进程不会更改缓冲区的内容那么它应该读取最新的内容,不是吗?

【问题讨论】:

  • fork 使用父地址空间的副本创建一个新进程。更改父进程中的buf 不会更改子进程中的buf
  • if ((__int64_t)(sem_child) == -1)?!?!?你为什么错误地尝试重塑MAP_FAILED
  • 这能回答你的问题吗? Using shared memory with fork()
  • 我认为这是一个误解,正如 kaylum 已经提到的那样。 cow 代表copy-on-write
  • buf [],应该在共享内存里面。现在它只是一个全局变量。 parent 和 child 的地址空间不同。所以buf在父子进程中是不同的。

标签: c++ linux


【解决方案1】:

感谢cmets,我现在了解copy-on-write

当父进程以forkexec执行系统调用时,prosess的内存页将被设置为只读,这些内存页将被复制到父/子进程空间,同时父/子进程尝试写入这些内存页内存页。

我错误地认为cow是子进程首先从父进程复制内存页。

【讨论】:

    最近更新 更多