线程

一,线程的概念

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<pthread.h>
#include<unistd.h>
#include<stdio.h>

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!\n");
    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())

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值