ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

linux与线程

2021-04-16 10:57:40  阅读:180  来源: 互联网

标签:rwlock int linux 线程 pthread 进程 cond


1.1.1 进程

在早期,人们都是为特定机器编写程序,并在其上运行计算任务(task)。渐渐的人们发现CPU与IO设备之间速度差太多了,往往CPU都在空转,是不是可以在CPU空闲的时候做些其他事呢?于是,就有了多任务(每个任务就是一个进程),有了资源调度,有了操作系统...

进程是资源管理的最小单位,操作系统在分配资源(内存,文件等)时是以进程为单位划分的。在单CPU(单核)的时代,通过对多个进程的调度(分配CPU时间片),我们已经可以边听音乐,边打游戏了!

在以前进程被描述为资源分配和执行调度的最小单位,但现在都不这么说了,因为引入了线程的概念。不管怎样,这些都只是一个名称而已,本质上还是要看资源是怎么分配和管理的。

本文不会讨论进程的调度算法,如FCFS,SJF,时间片轮转等。在这里,具体看一下Linux进程的数据结构,以及状态转换:

  • 进程的数据结构

 

 

 

linux进程是一个双端链表结构,其主要内容包括代码段,数据段,堆,栈,内存映射表等

  • 进程的状态转换

 

 

 

进程状态主要在就绪,执行,等待,每一次切换伴随着一次上下文切换。

  • 上下文切换

    进程的上下文包括进程在执行时,CPU所有寄存器中的值、进程的状态以及堆栈中的内容。所谓进程切换即一个进程获得或者丢失CPU时间片,这个过程由内核负责保存进程的状态快照(上下文),由此发生了上下文切换。可以看到这个过程本身就需要消耗很多CPU时间片。

总结: 虽然通过多进程调度,可以并发的处理任务,但可以看到进程的切换很频繁。一个进程刚得到CPU资源就又可能因为发生了IO阻塞而转入等待状态。一个进程在得到CPU时间片后如何充分利用它呢?于是又引入了线程的概念。

1.1.2 线程

为了最大效率的利用CPU,防止IO操作阻塞整个进程运行,降低进程上下文切换的开销,于是又引入了线程的概念,将线程作为CPU调度执行的基本单位。如果一个进程包含多个线程,则这多个线程可以并发或并行执行,并且线程不会导致进程的阻塞(理想情况或者理论层面来讲)。

为什么线程可以降低开销呢?对照上面进程内存结构图,进程的所有线程共享进程的数据结构,除了线程私有的像程序计数器,栈空间,寄存器之外。一个进程的线程之间切换不会发生系统调用,还有采用多线程可以更好的利用多处理器并行计算,线程直接通信更方便等等。

尽管线程有很多优点,但这都只是概念性的。并不是所有的操作系统都支持线程。windows原生支持了线程的实现,但linux中并没有线程的概念,所以只能通过在内核外实现多线程,根据线程的支持是在内核还是内核外,把线程划分为内核线程和用户级线程。

1.1.3 Posix线程标准

在讲Linux下线程实现之前,有必要先介绍一下posix线程标准。POSIX(Portable Operating System Interface)是一套接口API规范,有C语言描述,使用posix API编写的代码在遵循posix规范的平台间是可以移植的,JVM在linux系统上使用的就是pthread线程库作为底层实现。其中关于线程的API被称作pthread,该标准定义了从线程创建,通信,退出全部相关API(以pthread_开头)及其行为约束。

主要API:

函数前缀功能
pthread_线程本身及相关函数
pthread_attr_线程属性对象
pthread_mutex_互斥锁
pthread_mutexattr_互斥锁属性对象
pthread_cond_条件变量
pthread_condattr_条件变量属性对象
pthread_key_线程私有数据
pthread_rwlock_读写锁
pthread_rwlockattr_读写锁属性对象
pthread_barrier_屏障
pthread_barrierattr_屏障属性对象
pthread_spin_自旋锁

使用时引入头文件#include <pthread.h>:

//--------------------线程相关API--------------------//

/** 创建线程 */
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    void *(*start_routine)(void*), void *arg);
/** 等待线程结束 */
int pthread_join (pthread_t thread, void**value_ptr);
/** 退出线程 */
void pthread_exit(void *value_ptr);
/** 脱离线程: 将线程属性的分离状态设置为 detached,等待结束时回收资源 */
int pthread_detach (pthread_t thread);
/** 结束线程: 给线程发送中止信号 */
int pthread_kill(pthread_t thread, int sig);
/** 获取线程ID */
pthread_t pthread_self(void);

//----------------线程属性相关API-------------------//

/** 设置线程属性,pthread_create会用到 */
int pthread_attr_init(pthread_attr_t *attr);
/** 销毁线程属性 */
int pthread_attr_destroy(pthread_attr_t *attr);

//----------------互斥锁相关API--------------------//

/** 初始化互斥锁对象 */
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
/** 销毁互斥锁对象 */
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
/** 获取互斥锁(阻塞方式) */
int pthread_mutex_lock(pthread_mutex_t *mutex);
/** 获取互斥锁(非阻塞方式) */
int pthread_mutex_trylock(pthread_mutex_t *mutex);
/** 释放互斥锁 */
int pthread_mutex_unlock(pthread_mutex_t *mutex);

//----------------条件变量相关API------------------//

/** 初始化条件变量 */
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
/** 销毁条件变量 */
int pthread_cond_destroy(pthread_cond_t *cond);
/** 在条件变量上阻塞等待 */
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
/** 在条件变量上有时限等待 */
int pthread_cond_timedwait(pthread_cond_t *cond, 
    pthread_mutex_t *mutex, const struct timespec *abstime);
/** 唤醒一个在条件变量上等待的线程 */
int pthread_cond_signal(pthread_cond_t *cond);
/** 唤醒全部在条件变量上等待的线程 */
int pthread_cond_broadcast(pthread_cond_t *cond);

//----------------线程私有数据相关API------------------//

/** 设置线程私有数据 */
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
/** 删除线程私有数据 */
int pthread_key_delete(pthread_key_t key);

//----------------读写锁相关API------------------//

/** 初始化一个读写锁 */
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
/** 销毁读写锁 */
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
/** 读锁定(阻塞) */
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
/** 读锁定(非阻塞) */
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
/** 写锁定(阻塞) */
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
/** 写锁定(非阻塞) */
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
/** 释放读写锁 */
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

//----------------屏障相关API------------------//

/** 初始化一个屏障(栅栏) */
int pthread_barrier_init(pthread_barrier_t *barrier,const pthread_barrierattr_t *attr,        unsigned count);
/** 销毁屏障 */
int pthread_barrier_destroy(pthread_barrier_t *barrier);
/** 在屏障上等待 */
int pthread_barrier_wait(pthread_barrier_t *barrier);
复制代码

这里只列出了部分API,更多API可以使用man命令查看手册,熟悉pthreads api对理解java线程机制也很有帮助。

1.1.4 Linux线程支持

Linux中没有内核级线程的实现,所以只能在用户级别实现线程功能。比较著名的有早期的LinuxThreads,后来的NGPT以及NPTL。这些实现都利用了Linux提供的轻量级进程功能。

轻量级进程(LWP)就是对一个进程的拷贝(clone()系统调用),不过在进行拷贝时,可以有选择的只拷贝部分,clone底层调用内核do_fork方法:

int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, 	unsigned long stack_size)
复制代码

clone_flags就是要拷贝的内容,如LinuxThreads创建线程时,用CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND指定拷贝进程内存空间,文件目录,打开的文件表,信号处理器,注意,这里的拷贝表示在新的进程task_struct中将相关部分地址设置为与原进程相应地址相同,其实是共享相同内存,这个消耗相对普通进程会低一些。可以看到轻量级进程与线程非常相似,共享进程内存空间,打开的文件列表,信号等,也有自己私有的寄存器,栈空间等,但不能就此将轻量级进程与线程等同。

  • LinuxThreads

    LinuxThreads通过创建一个轻量级进程来创建一个线程,即一对一的线程模型,这样,线程的调度有os负责,而LinuxThreads通过一个管理线程(用户级)来管理像线程取消、线程间的同步的工作。通过这种方式模拟了一个进程包含一组线程的定义,但毕竟是模拟的,必然存在很多问题,如管理线程增加了线程创建的开销,线程数受到os进程数限制(后来linux版本有改进),无法利用SMP,线程间通信需要通过信号量的方式等等,以及与posix严重不兼容问题,正是由于种种问题,出现了一些其他新的线程库实现。

  • NGPT

    NGPT(Next-Generation POSIX Threads)是由IBM开发的一套新的用于取代LinuxThreads的线程库,不过并没有被广泛使用,现在已经不在维护了。

  • NPTL

    NPTL(Native POSIX Thread Library)是由Red Hat开发的另一套用于取代LinuxThreads的线程库。NPTL 不在使用管理线程,使用内核支持的进程共享信号及信号处理器,通过共享内存上实现futex功能来做线程同步,以及可以利用SMP特性等,理论上提高了多线程的性能,还有一个重要的点,基本支持posix标准。

    现在大部分平台线程库都是NPTL,可以通过getconf GNU_LIBPTHREAD_VERSION命令查看。

总结: 因为Linux没有原生语义的线程支持,所以在linux平台的线程都是使用轻量级进程来实现线程,这种方式是即有核外也有核内参与,在核内通过轻量级进程模拟,在核外实现线程语义(线程组,线程通信等)在一些地方称之为“混合式线程实现”。总而言之,可以知道,在linux平台一个线程就是一个轻量级进程。


作者:反认他乡是故乡
链接:https://juejin.cn/post/6844903997434757133
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:rwlock,int,linux,线程,pthread,进程,cond
来源: https://blog.51cto.com/u_15169172/2710227

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有