看看进程、线程的父子关系

线程的父子关系

    一般利用pthread库让让主线程去创建子线程,从而形成一个线程的父子关系。

    主线程调用pthread_join来等待子线程的结束,然后释放子进程占有的栈、id、私有数据等资源。这样设计阻塞的好处是父线程会等到子线程结束后才结束,这样不至于父线程关闭导致子线程没有结束就被关闭。可见父子线程默认情况下是有紧密联系的,父线程需要为子线程处理身后事。

    现在,我期望让父子线程没有关系,让子线程在结束的时候自己去释放自己的资源,那么需要调用pthread_detach来解开默认的父子关系。这样,父线程不再会顾忌子线程的结束与否。“不受约束”的子线程很可能因父线程的结束而异常关闭。

#include<iostream>
#include<pthread.h>
using namespace std;


void* fun(void*)
{
	pthread_detach(pthread_self());//父子关系的接触与否依赖于这句,可以观察有和没有的运行结果的区别。
	cout<<"fun begins!"<<endl;
	int i;
	for(i=0;i<1000000000;i++)
		;
	cout<<"fun is over! i="<<i<<endl;
	return NULL;
}


int main()
{
	cout<<"main begins."<<endl;
	pthread_t tid;
	int err = pthread_create(&tid, NULL, fun, NULL);
	void * tret;
	err = pthread_join(tid, &tret);
	cout<<"main is over."<<endl;
	return 0;
}

    从运行结果看出,在不调用pthread_detach的情况下,父线程会在pthread_join阻塞,等候子线程结束后再唤醒并结束。若调用了pthread_detach,父线程会直接关闭,导致子线程被迫关闭。


进程的父子关系

   一般利用系统调用fork在主进程创建子进程(见fork),从而形成一个父子进程。

    同样,一般要求父进程wait子进程结束的信号,然后去处理子进程的“身后事”,否则子进程将会变为僵尸进程(见《僵尸进程和孤儿进程》),显然属于父子关系处理不当的情况。如果父进程比子进程先结束,父子的关系会自然脱离,子进程变为孤儿进程,其“身后事”交给init办理。

    现在,我期望父子进程结束这种关系,成为两个独立的进程。对于线程来说,父子线程即使再怎么独立,也总是属于同一个进程的,因为共享了太多的资源。对于进程来说,父子进程的关系一旦解除之后,就可以认为进程没有关系了,子进程的身后事交给init来解决。

   APUE里提出一个fork两次的方法,通过创建了爷孙三代来使得进程关系彻底脱离,不过借助于第三个进程太麻烦了。利用系统调用setsid(void)就可以直接做到,setsid的作用是将当前进程加入到一个新的会话中。

#include<iostream>
#include<unistd.h>
using namespace std;

int main()
{	

	if(fork() != 0)
	{
		cout<<"father begins."<<endl;
		int i=0;
		for(;i<1000000000;i++)	;
		for(;i<1000000000;i++)	;
		for(;i<1000000000;i++)	;
		for(;i<1000000000;i++)	;
		for(;i<1000000000;i++)	;
		for(;i<1000000000;i++)	;
		cout<<"father is over. i="<<i<<endl;
	}
	else
	{
		cout<<"son begins."<<endl;
		pid_t pid = setsid();//有没有这句:父子关系是否脱离的区别
		cout<<"son is over."<<endl;
	}

	return 0;
}

程序运行起来,在另一个终端ps u观察进程的状态,可以看到父子关系是否脱离情况下子进程的状态的不同。从结果看出,不调用setsid的情况下,子进程提前结束会成为Zombie进程;调用setsid的情况下,子线程提前结束会完整释放其资源。

你可能感兴趣的:(看看进程、线程的父子关系)