CPU最小的调度单位—线程

前言

在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。(百度百科)

线程

定义:线程是一个正在运行的函数,如main线程
线程是调度器可以调度的最小单元,他被包含在进程中,他是独立分配和调度的基本单位,它可以实现并发,每个线程执行不同的任务。
在Linux系统中,使用的标准是posix,其他还有很多标准,如openmp线程
线程的标准pthread_t类型

pthread_equal函数

int pthread_equal(pthread_t t1, pthread_t t2);

作用:比较两个线程ID是否相等。

返回值:相等返回非0值,不等返回0值。

pthread_create函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
功能:该函数可以用于动态创建一个执行线程;
参数:thread 线程id,一般在创建完毕会自动赋值;
attr 线程属性,一般不用调整,用NULL 表示;
start_routine 指向指针函数的函数指针;
指针函数为: void * fun(void * arg);
函数指针为: xxx (*pfun)(void * arg);
===>pfun == fun ===>函数名字 ===》回调函数
===》线程的执行空间;

arg 线程回调函数的参数,即参数3的函数参数;
如果没有参数传递用NULL表示;

返回值:成功 0
失败 -1

1.在这个函数中,他的函数指针和参数都是viod*类型,这其中方便了我们使用任何类型
2.线程的调度取决于调度器的调度策略

线程的终止

三种方式:
1.线程从启动例程中返回,返回值就是线程的退出码

2.线程可以被同一进程中的其他线程取消 pthread_cancel();

3。线程调用pthread_exit()函数
void pthread_exit(void *retval);
功能:该函数用于线程自身结束并退出当前线程;
参数:retval 线程退出时候的返回值;
返回值:无

int pthread_cancel(pthread_t thread);
功能:该函数可以用于结束指定线程的运行;
参数:thread 要结束的目标线程tid号
返回值:成功 0
失败 -1;

子线程的资源回收: pthread_join()

int pthread_join(pthread_t thread, void **retval);
功能:该函数用于阻塞等待回收执行线程的资源。
参数:thread 要回收的目标线程tid;
retval 回收的目标线程返回值;如果不关心返回值用NULL;

返回值:成功0
失败 -1;
相当于进程中的wait()函数,都是用来收尸的
取消有两种状态:允许和不允许
允许取消又分为:异步cancel(默认)—推迟到cancel点
cancel点:POSIX定义的cancel,都是可能引发阻塞的系统调用
篇thread_setcelstate();设置是否要取消
thread_setceltype()设置取消方式

栈的清理

pthread_cleanup_push()/pthread_cleanup_pop()采用先入后出的栈结构管理
void pthread_cleanup_push(void (*routine) (void *), void *arg)
void pthread_cleanup_pop(int execute)
函数在调用pthread_cleanup_push()时压入清理函数栈,多次对pthread_cleanup_push()的调用将在清理函数栈中形成一个函数链,在执行该函数链时按照压栈的相反顺序弹出。execute参数表示执行到pthread_cleanup_pop()时是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行。
他们都属于是使用宏封装的,同时要注意,不管会不会执行到pop,都必须要有pop函数的存在,不然会报语法错误

互斥量

互斥的概念:
  是指散步在不同任务之间的若干程序片断,当某个任务运行其中一个程序片段时,其它任务就不能运行它们之中的任一程序片段,只能等到该任务运行完这个程序片段后才可以运行。最基本的场景就是:一个公共资源同一时刻只能被一个进程或线程使用,多个进程或线程不能同时使用公共资源。
同步的概念:
  是指散步在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。最基本的场景就是:两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。
定义: 在线程里也有这么一把锁——互斥锁(mutex),互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即上锁( lock )和解锁( unlock )。

【互斥锁的特点】:

  1. 原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;

  2. 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;

  3. 非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量
    参考链接:https://blog.csdn.net/daaikuaichuan/article/details/82950711
    总结他就是在访问共享资源的时候给他加上一锁,让其他的线程不会去改变,在操作完了以后再将锁打开,再重复加锁的时候会被阻塞等待

1、创建互斥锁:使用互斥锁类型定义一个全局变量;
pthread_mutex_t mutex;

2、初始化互斥锁:pthread_mutex_init
int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr);
功能:该函数用于互斥锁的默认初始化,将锁的默认属性生效;
参数:mutex 要初始化的目标互斥锁
atrr 要初始化的互斥锁属性值,一般NULL表示默认属性;
返回值:成功 0
失败 -1;
在单一的互斥量使用的时候,可以使用宏进行初始化PTHREAD_MUTEX_INIT

注意:一般在线程创建之前就要初始化互斥锁;

3、加锁:
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:该函数可以将某个区域的代码执行加锁操作
保证该部分代码的排他性访问;

参数: mutex 要加锁的互斥锁

返回值:0 成功 进程将会执行该行代码以后的其他语句
-1 失败 不会返回,会继续在该行代码位置阻塞等待解锁;

解锁:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:该函数的操作与加锁操作功能相反,用于已经加锁的
互斥锁进行解锁操作;
参数:mutex 要解锁的互斥锁
返回值:成功 0 互斥锁解锁
失败 -1

注意:加锁和解锁的目标对象针对的是代码行;
加锁==解锁之间的代码属于原子操作;

条件变量:

pthread_cond_t 条件变量
pthread_cond_init 初始化
pthread_cond_destroy销毁
条件变量的使用
int ead_cond_broadcast (pthread_cond_t *cond)广播的查询
int ead_cond_signal (pthread_cond_t *cond)单播的查询

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值