线程

线程概述

线程是操作系统能够进行运算调度的最小单位。它包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

线程的特点

1)轻型实体
线程中的实体基本上不用有系统资源,只有一点必不可少的、能保证独立运行的资源。
线程的实体包括程序、数据、TCB。线程是动态概念,它的动态特性由线程控制块TCB描述。

TCB包括以下信息:

  • 线程状态
  • 当线程不运行时,被保存的现场资源。
  • 一组执行堆栈
  • 存放每一个线程的局部变量主存区。
  • 访问同一进程中的主存和其他资源。

【TCB内容:用于指示被执行指令序列的程序计数器、保留局部变量、少数状态参数和返回地址等的一组寄存器和堆栈】
2)独立调度和分派的基本单位
在多线程OS中,线程是能够独立运行的基本单位,因而也是独立调度和分派的基本单位。由于线程很“轻”,故线程的切换非常迅速且开销小(同一进程中)。
3)可并发执行
在一个进程中的多个线程之间,可以并发执行,甚至允许在一个进程中所有的线程都能并发允许;同样,不同进程中的线程也能并发执行,充分利用和发挥了处理机与外围设备并行工作的能力。
4)共享进程资源
在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址;此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。
5)Linux中不区分进程、线程
6)使用多线程的好处
使用多线程大大提高了任务切换的效率,避免了额外的TLB&cache的刷新

线程的共享资源和私有资源

共享资源私有资源
可执行的指令线程ID(TID)
静态数据PC(程序计数器)和相关寄存器
进程中打开的文件描述符堆栈
当前工作目录错误号
用户ID优先级
用户组ID执行状态和属性

基于linux的线程操作

在Linux线程库pthread中提供了创建线程、回收线程、结束线程的基本操作,同时,线程的同步和互斥机制也是重点。

线程的创建——pthread_create

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

  • 头文件 #include<pthread.h>
  • 成功时返回0,失败时返回错误码
  • thread 线程对象
  • attr 线程属性,NULL代表默认属性
  • routine 线程执行的函数
  • arg 传递给routine的参数,参数是void * ,注意传递参数格式
    pthread_t pthread_self(void) 查看自己的TID

线程的回收——pthread_join

int pthread_join(pthread_t thread , void ** retval);

  • 头文件include<pthread.h>
  • 成功时返回0,失败时返回错误码
  • thread 要回收的线程对象
  • 调用线程阻塞知道thread结束
  • *retval 接受线程thread的返回值

线程的结束——pthread_exit

void pthread_exit(void * retval);

  • 头文件 #include<pthread.h>
  • 结束当前线程
  • retval可被其他线程通过pthread_join获取
  • 线程私有资源被释放

线程间通信

线程共享同一进程的地址空间,所以线程间通信很容易【通过全局变量交换数据即可】,在多个线程通信时,访问共享数据的时候需要用到同步和互斥机制。

线程通信——同步

同步指的是多个任务按照约定的先后次序相互配合完成一件事情,线程通信的同步机制由信号量来决定线程是继续运行还是阻塞等待

信号量(灯)

信号量代表某一类资源,某值表示系统中该资源的数量.
信号量是一个受保护的变量,只能通过三种操作来访问:
1)初始化
2)P操作(申请资源)【消费者】
3)V操作(释放资源)【生产者】

P操作含义如下:

if(信号量的值大于0{
	申请资源的任务继续运行;
	信号量的值减一;
}
else
{
	申请资源的任务阻塞;
}

V操作含义如下:

信号量的值加一;
if(有任务在等待资源)
{
唤醒等待的任务,让其继续运行;
}

Posix 信号量,posix中定义了两类信号量:

  • 无名信号量(基于内存的信号量)
  • 有名信号量

1)信号量初始化——sem_init
int sem_init(sem_t * sem , int pshared ,unsigned int val);

  • 头文件 #include<semaphore.h>
  • 成功时返回0,失败时返回EOF
  • sem 指向要初始化的信号量对象
  • pshared 0代表线程间 1代表进程间
  • val 信号量初值

2)信号量的P/V操作
int sem_wait(sem_t * sem); ——P操作
int sem_post(sem_t * sem); ——V操作

  • 头文件 #include<semaphore.h>
  • 成功时返回0,失败时返回EOF
  • sem 指向要P/V操作的信号量对象

线程间通信——互斥

临界资源: 一次只允许一个任务(线程、进程)访问的共享资源
临界区: 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问。当有线程进入临界区段时,其他线程或是进程必须等待,有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用。
互斥机制通过mutex互斥锁实现,任务访问临界资源前申请锁,访问完后释放锁。

互斥锁的初始化——pthread_mutex_init

在使用互斥锁之前,需要对互斥锁进行初始化。
int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);

  • 头文件 #include<pthread.h>
  • 成功时返回0,失败返回错误码
  • mutex 指向要初始化的互斥锁对象
  • attr 互斥锁属性,NULL代表缺省属性

申请锁——pthread_mutex_lock

int pthread_mutex_lock(pthread_mutex_t * mutex);

  • 头文件 #include<pthread.h>
  • 成功时返回0,失败返回错误码
  • mutex 指向要上锁的对象
  • 如果无法获得锁,任务阻塞

释放锁——pthread_mutex_unlock

int pthread_mutex_unlock(pthread_mutex_t * mutex);

  • 头文件 #include<pthread.h>
  • 成功时返回0,失败返回错误码
  • mutex 指向要释放锁的对象
  • 执行完临界区要及时释放锁

总结

同步机制与互斥机制还不熟练,需要加深!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值