编程发现,C语言中和C++11的标准库的进程确实在出错上有点不一样。
C++11会在有些披露的时候主动terminate,而C语言对有些行为是置之不理。
不过最重要的还是对于概念的认知了,把握好进程和线程,线程与线程之间的关系最为重要。
本帖先理一下关系,然后再分别讨论C和C++的处理。
1.进程,线程各种关系
(1)进程与线程
子进程和父进程,地址空间和描述符表,在fork的瞬间是相同但相互独立的。所有进程倒是共享同一张文件表。
但是若是资源回收,必然是父进程回收子进程。
线程都是依附于进程之上的,进程都结束了,线程必然会终止,哪怕是detach一个线程,它也不可能脱离进程,单独运行。
后面会再讨论detach的意义。
(2)线程与线程
线程与线程的关系,才是最吊诡的地方。
①同一个进程的各个线程之间是对等的。
任何线程可以回收其他线程,可以终止其他线程。
②初始线程与其他线程的关系。
初始线程就是说,最开始那个线程,它不是有我们调用函数而创造的,它和进程的关系最紧密,其他线程的创立都是经过它之手的。
它的特殊之处在于,很容易在关闭它的时候,将整个进程给关闭了,那其他的线程当然也就结束了。
注:刚刚有说到,任何线程可以回收其他线程,这个回收必须是要人家结束了,但是你还没有结束才行啊。
由于我们一般以初始线程来操作进程,所以我们一般以初始线程来回收其他未分离线程,然后在退出初始线程时,退出进程。
那我们可不可以终止最初线程,然后以其他线程来终止进程呢?
可以的。看下面的程序。
#include <pthread.h>
#include <unistd.h>#include <stdio.h>
void *fun(void *vargp)
{int i;
printf("hello, this is t2\n");
i = pthread_cancel(*((pthread_t *) vargp));
printf("pthread_cancel return %d, 成功cancel\n", i);
pthread_join(*vargp, NULL);
printf("over\n");
return;
}
int main()
{pthread_t t1, t2;
t1 = pthread_self();
pthread_create(&t2, NULL, fun, &t1);
pthread_detach(t2);
sleep(1);
return 0;
}
主函数中,我们首先声明两个进程,t1赋值最初进程的id。
接着将t2 associate fun函数,并且将t1的id作为参数,传入fun函数。
然后我们detach线程2,接着sleep1秒,sleep的目的是为了让t2线程先终止初始线程,而不至于进程已经退出了。
然后我们来看看,fun函数,也就是进程t2干些什么。
直接打印一句话,然后通过传递的指针,直接终止初始线程,通过pthread_cancel函数返回值,来判定杀死成功没有。
回收初始线程的资源,然后睡眠5秒,表示进程没有结束。因为如果进程控制权仍然在t1那里的话,进程会在sleep1秒后退出。
但是运行时你会发现,程序sleep了5秒,说明最后进程是由线程t2结束的。
2.C++11标准库的线程结束处理
我先直接给我的结论。
新建的子线程(也就是说不包括初始线程)在进程终止之前如果没有指定怎么回收资源(即没有指定join或者detach),那么进程一结束,就会出错。
下面来分辨,detach和join
join就是说,由当前的线程来回收调用join线程的资源。
detach就是说把该线程放到后台运行,由系统来回收资源。但是这个线程仍然在进程上,进程终止,这个线程当然就终止了。
只要指定了线程资源的回收方式,在进程终止时,就能正常回收,不出错。
3.C语言的pthread的结束处理
也有detach和join两个函数,但如果你根本不指定回收方式,在进程结束时也不会报错。