muduo库学习之C++多线程系统编程精要06——RAII与fork

东阳的学习笔记

审慎使用 fork()

fork()可能会导致资源泄漏

但是,假如程序会fork(),上面的假设就会被破坏了
考虑下面这个例子,Foo对象构造了一次,但是析构了两次

int main()
{
    
    
    Foo foo;    //调用构造函数
    fork();     //fork为两个进程
    foo.doit(); //在父子进程中都使用foo
 
    //析构函数会被调用两次,父进程和子进程各一次
}
  • 还可能会出现的错误:如果Foo class封装了某种资源,而这个资源没有被子进程继承,那 么Foo::doit()的功能在子进程中是错乱的。而我们没有办法自动预防这 一点,总不能每次申请一个资源就去调用一次pthread_atfork()吧?

子进程中的 继承不继承

  • fork()之后,子进程继承了父进程的几乎全部状态,但也有少数例外
  • **子进程会继承地址空间和文件描述符,**因此用于管理动态内存和文件描述符的RAII class都能正常工作
  • 但是子进程不会继承:
    • 父进程的内存锁,mlock、mlockall
    • 父进程的文件锁,fcntl
    • 父进程的某些定时器,setitimer、alarm、timer_create等等

更多见https://blog.csdn.net/qq_22473333/article/details/113481494#t3

RAII与fork()的相关注意事项

  • 通常我们会用RAII手法来管理以上种类的资源(加锁解锁、创建销毁定时器等等),但是在fork()出来的子进程中不一定正常工作,因为资源在fork()时已经被释放了
  • 比方说用RAII技法封装timer_create()/timer_delete():
    • 在子进程中析构函数调用timer_delete()可能会出错,因为试图释放一个不存在的资源
    • 或者更糟糕地把其他对象持有的timer给释放了(如果碰巧新建的timer_t与之重复的话)
  • 因此,我们在编写服务端程序的时候,“是否允许fork()”是在一开始就应该慎重考虑的问题,在一个没有为fork()做好准备的程序中使用 fork(),会遇到难以预料的问题

猜你喜欢

转载自blog.csdn.net/qq_22473333/article/details/113529880