Linux下线程相关知识总结

1.线程的基本介绍

(1)线程的概述

线程与进程类似,也允许应用程序并发执行多个任务的一种机制。一个进程可以包含多个线程,同一程序中的所有线程共享同一份全局内存区域,线程之间没有真正意义的等级之分。同一个进程中的线程可以并发执行,如果处理器是多核的话线程也可以并行执行,如果一个线程因为等待I/O操作而阻塞,那么其他线程依然可以继续运行

(2)线程优于进程的方面

argv,environ
主线程栈
线程3的栈
线程2的栈
线程1的栈
共享函数库共享的内存
未初始化的数据段
初始化数据段
文本

.进程间的信息难以共享。由于除去只读代码段外,父子进程并未共享内存,因此必须采用一些进程间通讯,在进程之间交换信息

.调用fork()来创建进程代价相对较高

线程很好的解决了上述俩个问题

.线程之间能够方便,快速的共享信息,只需将数据复制到共享(全局或堆)变量中即可

.创建线程比创建线程通常要快10甚至更多,线程创建之所以快,是因为fork创建进程时所需复制多个属性,而在线程中,这些属性是共享的。

(3)创建线程

启动程序时,产生的进程只有单条线程,我们称之为主线程

#include<pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void*(*start)(void *),void *arg);

新线程通过调用带有arg的函数开始执行,调用pthread_create()的线程会继续执行该调用之后的语句。

(4)终止线程

可以以如下方式终止线程的运行

.线程调用pthread_exit()

.线程start函数执行return语句并返回指定值

.调用pthread_cancel()取消线程

.任意线程调用了exit(),或者主线程执行了return语句,都会导致进程中的所有线程立即终止

pthread_exit()函数可以终止线程,且其返回值可由另一线程通过调用pthread_join()获得

#include<pthread.h>
void pthread_exit(void *retval);

调用pthread_exit()相当于在线程的start函数中执行return,不同之处在于,pthread_exit()可以在任何地方调用,参数retval指定了线程的返回值

(5)获取线程ID

#include<pthread.h>
pthread_t pthread_self(void);

线程ID在应用程序中主要有如下用途

.不同的pthreads函数利用线程ID来标识要操作目标线程。

.在具体的应用程序中,以特定线程的线程ID作为动态数据结构的标签,这颇有用处,既可用来识别某个数据结构的创建者或属主线程,又可确定随后对该数据结构执行操作的具体线程

函数pthread_equal()可检查俩个线程的ID是否相同

#include<pthread.h>
int pthread_equal(pthread_t t1,pthread_t t2);
//如果相同返回非0值,否则返回0

(6)连接已终止的线程

函数pthread_join()等待由thread表识的线程终止

#include<pthread.h>
int pthread_join(pthread_t thread,void **retval);
//返回0调用成功,否则失败

如果pthread_join()传入一个之前已然连接过的线程ID,将会导致无法预知的行为,当相同线程ID在参与一次连接后恰好为另一新建线程所重用,再度连接的可能就是这个新线程

若线程未分离,则就应该使用pthread_join()来连接线程,否则会产生僵尸线程

pthrea_join()函数的要点

.线程之间的关系是对等的,所以任意线程都可以调用pthread_join()来连接其他线程

.pthread_join()无法针对任意线程,只能连接单个线程

(6)线程的分离

默认情况下线程都是可连接的,但有时候,我们并不关心线程退出的状态,我们可以调用pthread_detach()并向thread参数传入指定线程的的标识符,将该线程标记为处于分离状态

#include<pthread.h>
int pthread_detach(pthread_t thread);
//返回0成功,否则失败

一旦线程处于分离状态,就不能在使用pthread_join()来获取其状态,也无法使其重返可连接状态

(7)在应用程序中如何来选择进程还是线程

.线程之间共享数据很简单,进程间的数据共享需要更多的投入

.创建线程要比创建进程块很多

.多线程编程时,需要确保调用线程安全的函数

.某个线程中的bug可能会危害进程中所有线程

.每个线程都在征用宿主进程中有限的虚拟地址空间

.在多线程应用中,需要小心使用信号

.除了数据,线程还可以共享文件描述符,信号处置,当前工作目录,以及用户ID和组ID

线程的同步

(1)保护共享变量访问:互斥量

线程的主要优势在于能够通过全局变量来共享信息,不过这种共享是有代价的。必须确保多个线程修改同一变量时,不会有其他线程也正在修改此变量,为避免线程更新时共享变量时所出现的问题,必须使用互斥量来确保同时仅有一个线程可以访问某项共享资源

(2)静态分配的互斥锁

互斥锁既可以像静态变量那样分配,也可以在运行时动态分配,互斥量属于pthread_mutex_t类型的变量,在使用之前必须对其初始化。对于静态分配的互斥量而言,可如下例所示,将PTHREAD_MUTEX_INITIALIZER赋给互斥量

pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;

1.加锁和解锁互斥量

初始化之后,互斥量处于未锁定状态。函数pthread_mutex_lock()可以锁定某一互斥量

而函数pthread_mutex_unlock()则可以将一个互斥量解锁

#include<pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//返回0成功,其他失败

要锁定互斥量,在调用pthread_mutex_lock()时需要指定互斥量,如果互斥量当前处于未锁定状态,则该调用将会立即返回,如果该互斥量已被其他线程锁定,那么该调用将会阻塞,直至互斥量被解锁

函数pthread_mutex_unlock()将解锁之前已遭调用线程锁定的互斥量

2.互斥量的性能

通常情况下,线程会花费更多的时间去做其他工作,对互斥量的加锁解锁相对要少的多,因此使用互斥量对大部分程序来说性能并无显著的影响

3.互斥量的死锁

当一个线程需要同时访问多个共享资源时,没个资源由不同的互斥索管理。当超过一个线程加锁同一组互斥量时,就有可能发生死锁。如下图所示

线程A

1.pthread_mutex_lock(mutex1);

2.pthread_mutex_lock(mutex2);

线程2

1.pthread_mutex_lock(mutex2);

2.pthread_mutex_lock(mutex1);

每个线程都成功的锁住一个互斥量,接着试图对以为另一线程锁定的互斥量加锁,就会一直等下去

要避免此类死锁问题,最简单的就是定义互斥量的层级关系

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 00:19:22

Linux下线程相关知识总结的相关文章

linux下grub相关知识详解

一.grub相关知识详解 (1)grub:GRand Unified Bootloader grub 0.x :grub legacy grub 1.x : grub2 grub legacy: stage1:mbr的bootloader阶段 stage1_5:mbr之后的扇区,让stage1的bootloader能够识别stage2所在分区的文件系统 stage2:磁盘分区(/boot/grub/) 配置文件:/etc/grub.conf-->/boot/grub/grub.conf stag

linux下分区相关知识

Linux 规定了主分区(或者扩展分区)占用 1 至 16 号码中的前 4 个号码.以第一个 IDE 硬盘为例说明,主分区(或者扩展分区)占用了 hda1.hda2.hda3.hda4,而逻辑分区占用了 hda5 到 hda16 等 12 个号码.因此,Linux 下面每一个硬盘总共最多有 16 个分区. 因此 hda1- hda4 是主区的意思. hda5以后是逻辑分区!! Linux下,每一个硬盘设备都被映射到一个系统的设备文件:对于磁盘,光驱等IDE或者SCSI设备也不例外. 此处要渗透一

linux下LVM相关知识(动态增减LVM,快照功能)的总结

一,什么是LVM LVM是逻辑盘卷管理(Logical Volume Manager)的简称,它是Linux环境下对磁盘分区进行管理的一种机制,LVM是建立在硬盘和分区之上的一个逻辑层,来提高磁盘分区管理的灵活性.LVM是磁盘分区和文件系统之间添加的一个逻辑层,来为文件系统屏蔽下层磁盘分区布局,提供一个抽象的盘卷,在盘卷上建立文件系统.物理卷(physical volume)物理卷就是指硬盘分区或从逻辑上与磁盘分区具有同样功能的设备(如RAID),是LVM的基本存储逻辑块,但和基本的物理存储介质

Linux系统的相关知识、常用命令及centos 7网卡配置

(本文仅为平时学习记录,若有错误请大佬指出,如果本文能帮到你那我也是很开心啦) 一.Linux系统的相关知识 1.Linux中根目录下所有文件夹的含义和用途(括号内为举例存放的文件) /  根目录 cd /  切换到根目录 / bin  存放可执行文件 /dev  存放设备文件  (网卡 CPU) /media  存放可移除设备文件   (U盘 CD/DVD  VMTools) /opt  存放第三方软件的默认位置 /tmp  存放临时文件  (日志文件) /root  root用户的家目录,主

Linux系统的相关知识、常用命令及拓展、centos 7网卡配置

一.Linux系统的相关知识 1.Linux中根目录下所有文件夹的含义和用途 目录 功能 /bin 存放可执行文件 /dev 存放设备文件 (如:网卡.CPU) /media 存放可移除设备文件 (如:U盘.CD/DVD.VMTools) /opt 存放第三方软件的默认位置 /tmp  存放临时文件 (如:日志文件) /root root用户的家目录,主文件夹 /home 普通用户的家目录,文件夹的命名是以用户的名字来命名的 /etc 存放配置文件 /usr 存放操作系统软件资源 /var 存放

Linux下线程pid和tid

#include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/syscall.h> struct message { int i; int j; }; void *hello(struct message *str) { printf("child, the tid=%lu, pid=%d\n",pthread_self(),syscall(SYS

linux下线程

linux下线程 线程与进程的关系: 之前转载的微信文章,进程与线程的差别已经说得比較清楚了.能够查看之前转载的文章.linux进程与线程的差别. 创建一个线程: #include<pthread.h> int pthread_creat(pthread_t * thread,pthread_attr_t * attr,void *(*stat_routine)(void *),void *arg); 惯例先写上函数原型: 參数:第一个參数pthread_t * thread 是一个指针,当进

Linux 下线程的理解

2017-04-03 最近深入研究了下Linux线程的问题,发现自己之前一直有些许误解,特记之-- 关于Linux下的线程,各种介绍Linux的书籍都没有深入去解释的,或许真的如书上所述,Linux本质上不存在线程的概念!在某种程度上的确是这样,但是难道LInux就只有一种进程的东西么??答案肯定是否定的!下面咱们慢慢分析 说起Linux下的线程,的确不如windows下来的直接,windwos中进程和线程有着明确的区分,各自有自己代表的数据结构.操作API,进程享有资源和线程参加调度.一切都是

linux下网卡相关查看设置

查整机硬件信息命令dmesg 查看网卡设备相关dmesg | grep eth 查看网卡eth0信息dmesg | grep eth0 使用ethtool命令查看指定网卡信息ethtool eth0 使用 mii-tool命令查看指定网卡情况mii-tool -v eth1 为了使用lspci命令需要安装以下软件包yum -y install pciutils 查看pci接口硬件信息lspci 在linux的proc文件系统中,通过查看/proc/net/dev文件可以得到每个网络接口的吞吐量c