【Linux】线程总结:初识、创建、等待、终止、分离

学习环境 :  Centos6.5 Linux 内核 2.6

Linux线程部分总结分为两部分:(1)线程的使用 ,(2)线程的同步与互斥。

第一部分线程的使用主要介绍,线程的概念,创建线程,线程退出,以及线程的终止与分离。

第二部分主要介绍在多线程环境下,使用同步与互斥保护共享资源,有互斥锁,条件变量,信号量,以及读写锁。

第一部分开始


初识线程

线程:也称轻量级进程(Lightweight Process , LWP),是程序执行流的最小单元。而多线程就是指,在一个进程中有多个执行流,在同时执行。

为什么需要多线程呢?

在客户端,我们需要界面和用户交互动作,此时就可以在后台线程去处理交互逻辑。比如下载一个文件利用一个线程,而同时还可以用一个线程响应用户的其他操作。

在服务端,如http服务器,会同时有多个请求需要处理,此时利用多线程可以大大提高请求的处理效率。

线程与进程的区别:

进程是资源分配的基本单位,而线程是调度的基本单元。操作系统中每一个执行的进程,都有它自己的地址空间,而同一进程中可以有多个线程,也就是多个执行流在同时执行。这里的同时,如果是单核处理器,则此时并不是真正意义上的同时,由于处理器运行速度很快,给每个执行流分配了时间片,在单核处理器中微观上还是顺序执行,而在多核处理器中,就是真正意义上的并行。由于同一进程的多个线程共享同一地址空间,因此线程之间有互相共享的资源,也有彼此独占的资源。

线程之间共享的资源主要有

  • 地址空间
  • 数据段和代码段
  • 全局变量
  • 文件描述符表
  • 信号处理方式(忽略或者有自定义动作)
  • 用户ID和组ID
  • 当前工作目录

每个线程各有一份的资源主要有

  • 线程ID
  • 上下文(寄存器,程序计数器,栈指针)
  • 栈空间
  • 状态字
  • 信号屏蔽字
  • 调度优先级

进程与线程的区别归纳如下几点:

1. 地址空间:进程间相互独立,每个进程都有自己独立的地址空间,同一进程的各线程间共享地址空间。某个进程内的线程在其他进程内不可见。
2. 通信关系:进程间通信有管道,消息队列,共享内存,信号量。线程间通信可以直接读写全局变量来进行通信。不管是进程还是线程,通信时可能出现数据不一致的情况,需要用同步互斥机制来保证数据的一致性。
3. 切换和调度:由于进程间独占数据段代码段等信息,所以切换进程的时候,需要把进程间独占的资源切换去,把要执行的进程资源换进来,而线程是进程的子集,共享大部分资源,切换时只需要保存上下文相关信息就好,所以线程切换的开销比进程切换的开销小。

线程的三种状态

线程主要有三种状态分别是就绪、阻塞、运行。

就绪:线程具备运行的所有条件,逻辑上已可以运行,在等待处理机。

阻塞:指线程在等待某一时间的发生,如I/O操作。

运行:占有处理器正在运行。

:关于进程与线程之间阻塞状态的关系,在文末做了个实验。

线程的控制

主要学习如何创建一个线程,线程有哪些终止方式,以及怎么获取一个线程的运行结果,判断线程是否异常退出,线程生命结束时有没有”遗言“。

这里学习的线程库函数由POSIX标准定义的,称为POSIX thread 或者 pthread。在Linux中函数位于libpthread共享库中,在gcc编译或者Makefile中记得要加上 -lpthread选项,用来指定要链接的库。函数在执行错误时的错误信息将作为返回值返回,并不修改全局变量errno,也就无法通过 perror() 打印错误信息。

创建线程

#include <pthread.h>

int pthread_create(pthread_t *thread, 
                   const pthread_attr_t *attr, 
                   void *(*start_routine)(void *), 
                   void *arg);

描述:创建一个线程,用第一个参数线程标识符,第二个参数设置线程属性,第三个参数指定线程函数运行的起始地址(函数指针),第四个参数是运行函数的参数。

实例:下面的代码创建了两个线程,并分别在线程中调用pthread_self()打印各自的线程ID,以及调用 getpid() 打印进程ID,为了对比也在创建线程的Main执行流中打印线程ID,和进程ID。

#include <stdio.h>
#include <pthread.h>    // pthread_create()
#include <unistd.h>     // sleep()
#include <sys/types.h>  // getpid()

// 打印每个线程的ID, 和进行ID

void * run_1(void *arg)  // 线程1 执行代码
{
    sleep(1);
    printf(" thread 1 tid is  %u,  pid is %u \n", pthread_self(), getpid()); 
}

void * run_2(void *arg)  // 线程2 执行代码
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值