线程学习(一)

线程概念:

           通常来说,线程是一个程序的一条执行流,更准确来讲是一个进程内部的控制序列。在Linux下线程是用PCB模拟的,线程也被称作轻量级进程,因此Linux下的线程是CPU调度的基本单位(与传统系统相比Linux下没有真正的线程)。由于线程是在进程内部运行的执行流,所有线程共享进程资源。

线程优缺点:

           优点:

                    1.  创建一个线程代价要比创建一个进程小的多;

                    2.  与进程之间的切换相比,线程间的切换需要系统做的工作比较少;

                    3.  线程间通信比较方便;

                    4.  线程占用资源比进程少很多;

                    5.  在等待较慢的IO操作时,程序可以执行其他任务;

                    6.  计算密集型应用,为了能在多处理器系统上运行,将计算分解到多线程中计算;(分摊计算)

                    7.  IO密集型应用,为了提高性能将IO操作重叠,线程可同时等待不同的IO操作。   (分摊等待)

            缺点:

                    1.  增加了调度的开销和成本,消耗过多的CPU,造成性能损失;

                    2.  线程间共用同一块地址空间,所以每个线程会受限于地址空间大小;

                    3.  健壮性降低;

                    4.  缺乏访问控制;

                    5.  多线程对临界资源进行操作容易造成资源混乱;

                    6.  如果一个线程异常,将会造成所有线程异常。

延伸:1.  比较进程与线程:

         进程是分配系统资源的基本实体;

         线程是CPU调度的基本单位;

         我们知道进程的独立性:每个进程都有自己的虚拟地址空间,页表,映射关系,物理内存,数据。同样的线程也有自己的栈角和数据(线程id,一组寄存器,信号屏蔽字,调度优先级,error)。

           2.  线程间共享那些资源?

  •    文件描述符表 
  •    信号处理方式
  •    工作目录
  •    用户ID和组ID          

           3.  线程实现方式:

内核支持线程 KST 

优点:

  1. 多线程可以并行处理;
  2. 如果进程中一个线程阻塞,其他进程依然可以运行;
  3. 内核支持线程具有很小的数据结构和栈,切换比较快,开销小;
  4. 内核本身为多线程,可以提高系统执行速度和效率。

缺点:

     与用户级线程相比,其模式切换开销较大(因为需要从用户态切换到内核态),对系统消耗大。

  • 用户级线程 ULT

优点:

  1. 线程切换不需要转换到内核空间,只在用户态完成;
  2. 调度算法可以是进程专用的;
  3. 用户级线程的实现与操作系统平台无关。

缺点:

  1. 线程阻塞问题;
  2. 单纯的用户级线程实现方式中,多线程应用不能利用多处理机进行多重处理的优点,即系统只为进程分配一个CPU,每次仅有一个线程能执行,其他只能等待。
  • 组合方式:

          1.  多对一,将用户线程映射到一个内核线程。

               优点:线程管理开销小,效率高。

               缺点:线程阻塞问题;多个线程不能在多处理机上执行。

          2.  一对一,将每个用户线程对应一个内核线程。

              优点:没有线程阻塞问题;多线程可以在多处理机上执行。

              缺点:占系统内核开销大,所以对线程数量要加以限制。

          3. 多对多,许多用户进程映射少量内核线程。

              兼容上述优点,消除上述缺点。

线程控制:

           操作系统并没有提供相应实现线程控制的系统调用接口,但有为线程控制封装的线程库。使用这套接口创建的线程称为用户态线程,它在操作系统内部提供了一个轻量级进程

           线程创建:         

 /*
     通过参数返回一个用户态的线程id(是线程地址空间在进程虚拟地址空间中的首地址),
   用户态线程的操作都是围绕这个用户态的线程id来操作的。
 */
 #include <pthread.h>
       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

 

           /*

                      thread             // 返回线程ID

                      attr                  // 设置线程的属性,attr为NULL表⽰使⽤默认属性

                      start_routine   // 是个函数地址,线程启动后要执⾏的函数

                      arg                  // 传给线程启动函数的参数

                      返回值:  成功返回 0;  失败返回错误码

           */

PID实际上是tgid(线程组id) LWP就是线程pcb的pid

PID实际上是tgid(线程组id);   LWP就是线程pcb的pid

           


           线程等待:

                      作用:主线程获取新线程的退出状态,避免产生僵尸进程。

                      属性:

  • 只能等待指定的线程;
  • 只有线程处于joinable状态(线程默认属性),这个线程才能被等待。
  • 线程分离:线程退出后,直接释放资源,无法获取返回值。

 

#include <pthread.h>
       int pthread_join(pthread_t thread, void **retval);  

                      /*

                             thread        // 线程ID

                             value_ptr   // 它指向⼀个指针,后者指向线程的返回值

                             返回值: 成功返回0 失败返回错误码

                      */


           线程分离:

                     由于新线程创建出来后,主线程必须进行等待,线程等待是阻塞的,此时主线程什么都不能做。线程分离,将新线程分离出去,当新线程结束后自动退出,释放资源,主线程不需要再关心新线程退出

  • 可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离。
  • joinable和分离是冲突的,一旦线程被分离将不能再被等待。
    #include <pthread.h>
       int pthread_detach(pthread_t thread);

           线程终止:

  • 从线程函数return(),线程就退出了。
  • 主线程就是从main()函数退出,主线程退出即进程结束。
  • 主线程要等待其他线程退出(线程等待),否则会出现类似僵尸进程的情况,出现内存泄漏。
/*
   线程退出 ---> 主动退出(谁调用谁退出) 
*/
#include <pthread.h>
       void pthread_exit(void *retval);  

             线程取消:

                       取消执行中的一个线程。

/*
    线程取消 ---> 被动退出(退出被调用的线程)
*/
#include <pthread.h>
       int pthread_cancel(pthread_t thread); 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值