线程

2019-07-14 11:15发布

一,线程的概念

1,线程是操作系统能够进行运算调度的最小的单位。 2,线程被包含在进程中,是进程中实际运作的单位。就是说,线程在进程的地址空间里运行。 3,一条线程指进程中一个单一顺序的控制流。 4,一个进程中可以并发多个线程,每条线程的执行任务不同。 5,从内核的角度理解线程。         在内核中看到的线程也是PCB来表示的,创建新的PCB和原PCB共用虚拟地址空间。         Linux中使用进程来模拟实现线程,这种线程也被称之为轻量级进程。         也就是说在Linux看来,没有什么线程和进程的区别,这样也就统一了线程和进程的管理。

二,线程与线程的联系

1,线程没有高低之分,每个线程都是等级都是一样的。 2,同一进程内部的线程间共享部分资源。                1,同一虚拟地址空间,(本质上式多个线程的PCB公用同一个页表)                     因此代码,全局数据,堆都是共享的,加入定义一个函数,那么在各个线程中都可以调用,                     定义一个全局变量,在个线程中都能访问。                     就是说:两个进程间肯定不能访问同一个函数,                     因为根本就不再同一个地址空间中,但是两个线程可以,因为他们公用了同一地址空间。                2,文件描述符表。 3,线程间也有私有的空间                1,独立的调用栈。要是共用同一调用栈,多个进程切换使用就会把调用栈写坏了。                2,上下文信息。                  

二,线程与进程的对比

什么叫进程:用一组PCB来表示,用途是资源的分配和管理 什么叫线程;  用一个PCB来表示,用途是资源的调度和执行  举个例子:                
  • 打开迅雷软件—–向系统内核索要资源,启动“迅雷”进程,。
  • 开始下载一个电影—–从索要的资源中调度分配一部分资源,启动下载线程。
  • 开始播放电影—–再索要的资源中调度分配一部分资源次从,启动播放线程。
  线程的优点:                       1,线程占用的资源要比进程少,创建一个新线程的代价更小,意思就是和主线程公用一份地址空间。
                      2,线程间的切换也更简单,需要操作系统做的工作更少。                       3,线程之间共享数据更容易。 线程的缺点:                         1,编码/调试的难度提高。                         2,缺乏访问控制:一个线程崩溃,会导致整个进程都异常终止。(因为他们公用虚拟地址空间)    

二,线程的控制

系统调用:就是操作系统内核所提供的一些功能,然后以一些c语言风格的函数接口,暴露给用户。(如 fork,wait,exec)。 操作系统并没有提供线程的概念,用户态才有线程的概念。 所以并没有什么直接操作线程的系统调用,线程的相关操作都是以库函数的形式提供的(posix线程库)。

1,创建线程函数

int pthread_create (pthread_t * thread ,const pthread_attr_t *attr, void*(*start_routine)(void*),void* arg); 参数:         thread:输出型参数 ,将返回这个线程的id;          attr:一般填空,表示默认          start_routine:函数指针,这个函数就是这个线程将要执行函数。          arg:要执行函数的参数。有多个的话就传结构体。 返回值:         成功返回0,失败返回错误码

2,编写一个简单的线程代码

//p表示POSIX 线程库 #include #include #include void* Enter(void* arg) { (void) arg; while(1) { printf("I am thread"); sleep(1); } } int main () { pthread_t tid; pthread_create(&tid,NULL,Enter,NULL); while(1) { printf("I am main! "); sleep(1); } return 0; }     现再来看看是否有是两个线程了,具体就是查看是否有两个PCB 然后来查看进程组的PCB   图中的Thread和LWP都是线程ID,但是两者属于不同的范畴             Thread:是属于线程库的范畴,线程库的后序操作都是根据这个线程ID来完成的。使用thread_self(),可以获得。                            从图中它是一个地址,其实就是地址空间中这个线程的地址。             LWP:    是属于进程调度的范畴。但是线程是轻量级进程,使用这个ID,无法调度,所以有了Thread。 那么一个进程就是由若干个线程构成的,起码有一个,就是主线程,这若干个线程叫线程组。 线程组的id就是进程的id,就是主线程的id。    

3,线程终止函数

      1, 线程自己return返回       2,线程在内部调用pthread_exit函数结束自己。        void pthread_exit(void * value_ptr) //value_ptr不能是栈变量        3,一个线程使用pthread_cancel函数结束掉同一线程组的某个线程。 int pthread_cancel (pthread_t tid) //tid 就是 线程ID   强烈不推荐使用第三种方法。

4,线程的等待和分离

为什么需要线程等待?        已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。 创建新的线程不会复⽤刚才退出线程的地址空间        就是说,等到线程结束主线程需要将已退出的线程的资源进行清理。 int pthread_join (pthread_t thread , void ** value_ptr) 一般都将参数类型设为void*,因为 一个无类型的指针,大小是固定的,将两边都设为void*,就能实现传参, value_ptr是 void* * 再加一个* 是为了传指针,做输出参数,函数返回就可直接用value_ptr了 thread :线程ID value_ptr:输出的参数 返回值:成功返回0 void**value_ptr:这是一个输出参数,线程以不同的方式结束,这个输出的参数的值也是不一样的。                            如果是return方式返回,value_ptr就是return的值的指针。                            如果是pthreadexit 方式返回,value_ptr 就是传给pthread_ptr函数的参数(value_ptr)的指针。                            如果是pthread_cancel的方式返回,value_ptr就是一个常数的指针。                            如果不关心就填空。 线程分离: 1,另一个线程分离另一个线程 int pthread_detach(pthread_t tid) 2,线程自己分离自己 int pthread_detach(pthread_self())          

热门文章