线程和fork
来源:互联网 发布:word2003软件 编辑:程序博客网 时间:2024/05/21 10:36
一、简介
当线程调用fork时,就为子进程创建了整个进程地址空间的副本,父子进程通过写时复制技术来共享内存页的这一副本。
子进程通过几成整个地址空间的副本,也从父进程那里继承了所有互斥量、读写锁和条件变量的状态。如果父进程包含多个线程,子进程在fork返回后,如果紧接着不是马上调用exec的话,就需要清理锁状态。
在子进程内部只存在一个线程,它是由父进程中调用fork的线程的副本构成的。如果父进程中线程占用锁,子进程同样占用这些锁。问题就是子进程并不包含占用锁的线程的副本,所以子进程没办法知道它占用了哪些锁并需要释放哪些锁。
1、在子进程从fork返回后立马调用exec函数,可以避免这个问题。这种情况下,老的地址空间被丢弃,所以锁的状态无关紧要了。但如果子进程需要继续做处理工作的话,这种方法就行不通了,所以还需要其他策略。
2、另一种方法就是通过调用pthread_atfork函数建立fork处理程序。其原型如下:
#include <pthread.h>int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));这一函数的作用是为fork安装三个帮助清理锁的函数。其中:
prepare函数由父进程在fork创建子进程之前调用,这个fork处理程序的任务是获取父进程定义的所有锁;
parent函数在fork创建子进程后,但在fork返回之前在父进程环境中调用的,其任务是对prepare获取的所有锁进行解锁;
child函数是在fork返回前在子进程环境中调用的,和parent函数一样,child函数也必须释放prepare处理函数中的所有的锁。
重点来了,看似这里会出现加锁一次,解锁两次的情况。其实不然,因为fork后对锁进行操作时,子进程和父进程通过写时复制已经不对相关的地址空间进行共享了,所以,此时对于父进程,其释放原有自己在prepare中获取的锁,而子进程则释放从父进程处继承来的相关锁。两个并不冲突。
下面是一段代码,用来重现此现象:
#include "apue.h"#include <pthread.h>pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;voidprepare(void){printf("preparing locks...\n");pthread_mutex_lock(&lock1);pthread_mutex_lock(&lock2);}voidparent(void){printf("parent unlocking locks...\n");pthread_mutex_unlock(&lock1);pthread_mutex_unlock(&lock2);}voidchild(void){printf("child unlocking locks...\n");pthread_mutex_unlock(&lock1);pthread_mutex_unlock(&lock2);}void *thr_fn(void *arg){printf("thread started...\n");pause();return(0);}intmain(void){interr;pid_tpid;pthread_ttid;#if defined(BSD) || defined(MACOS)printf("pthread_atfork is unsupported\n");#elseif ((err = pthread_atfork(prepare, parent, child)) != 0)err_exit(err, "can't install fork handlers");err = pthread_create(&tid, NULL, thr_fn, 0);if (err != 0)err_exit(err, "can't create thread");sleep(2);printf("parent about to fork...\n");if ((pid = fork()) < 0)err_quit("fork failed");else if (pid == 0)/* child */printf("child returned from fork\n");else/* parent */printf("parent returned from fork\n");#endifexit(0);}运行结果如下(假设子进程先运行):
$ ./a.outthread started...parent about to fork...preparing locks...child unlocking locks...child returned from forkparent unlocking locks...parent returned from fork可以看出,prepare函数在调用fork后运行,child在fork返回到子进程之前运行,parent在fork返回到父进程前运行。
- 线程和fork
- 线程和fork
- 线程和fork()
- 线程和fork
- [APUE] 线程和fork
- 线程和fork
- 线程和fork-
- Linux Advance--线程和fork
- Linux中进程、线程和fork()
- 《Unix环境高级编程》:线程和fork
- fork() || fork()和fork() && fork()笔试题
- fork() || fork()和fork() && fork()笔试题
- fork() || fork()和fork() && fork()笔试题
- 关于“线程和fork”的一些疑问和猜想
- UNIX环境高级编程——线程和fork
- UNIX环境高级编程——线程和fork
- 《UNIX环境高级编程》笔记--线程和fork
- 并行处理:分叉(fork)和线程(thread)
- MySQL设置binlog日志的有效期自动回收
- 古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?
- Linux下安装awstats日志统计分析
- Oracle内连接、外连接、右外连接、全外连接小总结
- C#学习笔记之集合(入门经典 11.)
- 线程和fork
- C++模板实现的单向链表
- MySQL导入乱码解决
- Linux下重置MySQL的Root帐号密码
- ZendStudio9之SVN项目代码提示丢失解决
- C# mysql 链接 遇到 异常 Authentication with old password no longer supported, use 4.1 style passwords.
- 阿里云Linux服务器挂载硬盘分区
- 工作计划
- tar命令结合find搜索将指定条件的文件进行打包压缩