Linux线程的操作以及与进程的区别
2017-06-15 15:34
435 查看
线程的概念
Linux中不仅有进程这一概念,还有线程这一概念。简单来说,线程是指:在一个进程中,不同的执行流。线程的大部分概念和进程相似,所以他们有很大的相同之处。多线程之间的切换和调度就好像进程间的切换和调度一样,他们都在进程的地址空间运行,所以多线程之间可共享一些资源:1、文件描述符表;
2、每种信号的处理方式;
3、当前工作目录;
4、用户id和组id;
但是线程之所以是线程,区别之处就在于下面这些多线程间不能共享的资源:
1、线程id;
2、上下文信息,包括各种寄存器,程序计数器和栈指针;
3、栈空间;
4、errno变量;
5、信号屏蔽字;
5、调度优先级
这些之中我们主要理解栈空间和上下文,线程之间的栈空间不同的话,则他们必不会相互干扰,只在自己的栈帧里面运行。上下文信息,寄存器、程序计数器、栈指针这些东西都是标记一个“进程”被切换后,能正确回到自己原先的位置继续运行,标记该“进程”的计数或该“进程”中的指针位置。
很大程度上,线程就像一个缩减版的进程,所以Linux中我们把线程也叫做:“轻量级进程(LWP)”。
试想:我们在一个程序之中,需要执行两个不同的执行流之时,根据以前的方法,我们肯定会不假思索的fork一个子进程。很正确,但是一个进程就有自己PCB、页表、mm_struct…很多东西,这可能会给我们的操作系统或服务器带来很大的负担。但是,在合适的时候创建线程就可以避免这些问题,因为一个进程可以创建多个线程,而只需要一个PCB。
线程创建:
线程的创建:#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
首先,在使用pthread_create这个函数之前,我们必须要有一个线程id,直接使用 pthread_t定义即可。第二个参数表示线程的属性,目前我们不关心,设置为NULL即可;第三个参数很明显是个函数指针,表明创建的这个线程的执行分支,就是这个函数指针里面的内容;第四个参数依旧设置为NULL,使系统指定为我们生成。
这个函数的返回值为“int”,但这个作用并不大,主要是它会产生两个执行流,一个为主执行流,另外一个为分支执行流。主执行流即为当前作用域中pthread_create下方的代码,分支执行流即为函数指针表示的那个函数。
获得线程id:
#include <pthread.h> pthread_t pthread_self(void);
线程被创建出来,当然要在执行完毕之后对其进行回收,这就跟进程中子进程退出后父进程会对子进程进行回收一样。
#include <pthread.h> int pthread_join(pthread_t thread, void **retval);
val为“**”,目的是为了拿回pthread_create中传参的函数指针的函数的返回值。
因为函数指针的参数为void*,为一个一级指针就够,所以为了将其拿出来,用户使用或其他我还不知道的地方使用,就需要传一个二级指针进去,将其取出。
线程的退出:
可以使用pthread_exit()退出,注意不是exit,exit会直接退出进程。
#include <pthread.h> int pthread_cancel(pthread_t thread);
取消函数,可以自己取消自己,也可以别人取消。线程被取消时,会返回宏PTHREAD_CANCELD表示((void*)-1)。
#include <stdio.h> #include <pthread.h> #include <unistd.h> pthread_t tid1,tid2; void func() { printf("tid1-->hello,world~\n"); printf("tid1-->hello,world~\n"); printf("tid1-->hello,world~\n"); printf("tid1-->hello,world~\n"); printf("tid1-->hello,world~\n"); } void *fun1(void *val) { func(); printf("tid1-->fun-->I am a thread,tid: %u\n",pthread_self()); // pthread_exit((void*)1); printf("tid1-->process pid: %d\n",getpid()); // sleep(2); } void *fun2(void *val) { printf("tid2-->I am fun1\n"); return (void*)1; } int main() { void* tmp; pthread_create(&tid1,NULL,fun1,NULL); printf("tid1-->process, pid: %d\n",getpid()); sleep(1); printf("main-->I am a thread,tid: %u\n",pthread_self()); if(0==pthread_join(tid1,&tmp)) { printf("pthread_join success\n"); } pthread_create(&tid2,NULL,fun2,NULL); printf("tid2-->process, pid: %d\n",getpid()); sleep(1); if(0==pthread_join(tid2,&tmp)) { printf("pthread_join success\n"); } printf("tmp:%d\n",tmp); return 0; }
我们可以发现,线程间的运行貌似也遵守进程那样的调度原则来运行线程,所以这个运行的先后次序会发生改变。具体到哪一个线程什么时候运行,运行多长时间关系到系统分配的时间片的问题。
线程的分离与结合:
线程有两个属性:结合与分离。一般默认情况下,线程的属性为结合属性,此属性下,当前线程乐意被其他线程杀死或回收,再被其他线程回收之前,它的资源时不释放的。相反,分离属性下,一个线程是不可以被杀死或回收的,它的存储器资源在线程终止时由操作系统回收。默认情况下的设置,是为了防止存储器泄漏。要保证,一个线程能被显式的回收,可以使用pthread_join函数回收,也可以分离此线程,使用pthread_detach。 如果⼀一个可结合线程运行结束后但没有被join,则它的状态类似于进程中的Zombie Process, 即还有⼀部分资源没有被回收,所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源。
由于调⽤用pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我 们并不希望如此。例如,在Web服务器中当主线程为每个新来的连接请求创建⼀一个⼦子线程进 行处理的时候,主线程并不希望因为调⽤用pthread_join而阻塞(因为还要继续处理之后到来 的连接请求),这时可以在子线程中加入代码 pthread_detach(pthread_self()) 或者⽗父线程调用 pthread_detach(thread_id)(非阻塞,可立即返回) 这将该子线程的状态设置为分离的(detached),如此⼀来,该线程运行结束后会自动释放所有资源。
即线程的分离时可以自己分离自己,也可以由别人分离自己。
分离线程的创建:
#include <stdio.h> #include <pthread.h> pthread_t tid; void* fun(void* val) { //pthread_detach(pthread_self()); printf("I am a thread:%u\n",pthread_self()); printf("%s\n",(char*)val); return (void*)1; } int main() { pthread_create(&tid,NULL,fun,"pthread runnning..."); pthread_detach(tid); sleep(1);//沉睡一秒,保证系统回收动作完成 if(pthread_join(tid,NULL)==0) { printf("pthread_join success!\n"); } else { printf("pthread_join failed!\n"); } return 0; }
如有错误,请指出!
相关文章推荐
- 【Linux/OS/Network】线程以及其与进程区别
- Linux下多个进程或线程同时对一个文件进行写操作
- Linux中线程和进程的区别
- 进程与线程区别以及进程间通信方式
- 进程和线程以及两者的区别
- 线程与进程区别以及线程作用
- 进程与线程的区别以及通信方式
- Linux进程虚拟地址空间的分布、以及堆和栈的区别
- Linux中进程和线程的对比与区别
- Linux进程与线程的区别
- linux下对进程与线程基本操作常用命令
- 进程和线程以及区别
- linux 寻找出当前正在运行的进程以及线程(一条命令)
- 报名:《Linux的进程、线程以及调度》4节系列微课(5.22-25)
- Devik 进程,linux 进程,线程的区别
- 进程和线程的区别(Linux)
- 从进程和线程定义及区别谈起,包括linux环境下进程和线程的常见函数
- linux进程与线程的区别
- 进程和线程的区别以及联系
- 进程 线程 的区别以及 通信方式