Linux:线程

线程

  • 进程:运行中的程序,资源分配的基本单位
  • 线程:进程内部的一条执行路径,调度/执行的基本单位
    • 实现
      • 用户级:一条执行路径(内核)模拟三条执行路径(用户)
        开销小,但无法使用多个处理器
      • 内核级:内核支持,开销较大,内核直接管理,利用多处理器
      • 组合/混合模型:两个组合,多线程,利用多处理器

Linux:内核级,将所有线程都当做进程来实现,将线程视为与其他进程共享某些资源的进程,每个线程都有自己的PCB。(Windows具有支持线程的机制)

多线程

并发执行(交替,同时)

多核,拆分

#include<pthread.h>
//创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
//thread:保存创建线程的ID
//attr:指定线程属性。NULL
//start_routine:线程函数指针
//arg:传递线程函数的参数
//返回值:0,成功


//退出线程
void pthread_exit(void *retval);
//retval:用于退出线程时返回信息

//等待指定线程退出,阻塞
int pthread_join(pthread_t thread, void **retval);
//thread: pthread_create创建线程的id
//retval: 接收pthread_exit退出线程时返回的信息

编译链接时需要指定库: -pthread.

主线程运行时间短,其他线程还未运行,整个进程直接结束
所有线程同时访问一个资源,冲突,指令(多核并行)

线程同步

  • 信号量
#include <semaphore.h>
//初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
//sem:保存初始化信号量的地址
//pshared:进程间共享;0,否
//value:初始值

//P操作
int sem_wait(sem_t *sem);
//sem:保存信号量的地址

//V操作
int sem_post(sem_t *sem);
//sem:保存信号量的地址

//销毁信号量
int sem_destroy(sem_t *sem);
//sem:保存信号量的地址
  • 互斥锁
    相当于初始值为1的信号量
#include <pthread.h>
//初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//mutex: 保存初始化互斥锁的地址
//attr: 指定互斥锁属性,NULL

//加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
//mutex: 保存初始化互斥锁的地址

//解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//mutex: 保存初始化互斥锁的地址

//销毁互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//mutex: 保存初始化互斥锁的地址

生产者/消费者模型

有限缓冲问题

  • 多线程共享同一个缓冲区,生产者线程添加数据,消费者线程读取数据(管道?)
    • 互斥的使用缓冲区
    • 缓冲区空,不能读取
    • 缓冲区满,不能添加
  • 解耦:不直接互相调用,不影响对方,将两者之间的强耦合解开,变成三者之间的弱耦合
  • 支持并发:不需要等待对方操作,并发执行
  • 支持忙闲不均:双方直接操作速度不均衡浪费CPU时间片,加入缓冲区达到动态平衡

条件变量

线程之间同步共享数据的值
通知机制:
当某个共享数据的值达到某个值时,唤醒等待该数据的线程

#include <pthread.h>
//初始化条件变量
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
//cond:保存条件变量的地址
//attr: 设定条件变量的属性

//唤醒等待条件变量的所有线程
int pthread_cond_broadcast(pthread_cond_t *cond);
//唤醒一条线程
int pthread_cond_signal(pthread_cond_t *cond);
//cond: 条件变量

//将某个线程加入到等待条件变量的队列
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
//cond: 条件变量
//mutex: 互斥锁,用于保护条件变量,确保wait操作的原子性
//       wait过程:在外部先加锁,waite内先解锁,然后加入队列,阻塞并休眠,当唤醒时,首先加锁,然后执行线程的程序,最后考虑在外部进行解锁
//       此过程期间唤醒操作无法改变条件变量队列,考虑在唤醒操作前后添加锁操作,保护条件变量;当wait能够加锁时,才得以成功唤醒
//       (多核多线程)当存在多线程同时等待某个条件时,需要进行条件判断(while),以保证只有一个进程进入临界区,避免唤醒异常,重新进入阻塞状态

int pthread_cond_destroy(pthread_cond_t *cond);
//cond: 条件变量

读写锁

  • 允许同时读
  • 不允许同时写,同时读写
#include <pthread.h>
//读写锁初始化
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
//rwlock: 保存初始化读写锁的地址
//attr:指定读写锁属性,NULL

//销毁读写锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
//读锁,允许多个线程进程读取操作
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
//写锁,只允许一个进程进行写操作
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
//解锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
//rwlock: 读写锁

线程安全:多线程程序的结果不受调度(线程)顺序的影响

  • 同步:信号量,锁
  • 线程安全函数,可重入函数(一个函数被多线程同时调用结果不出现异常)
  • 静态/全局变量,多线程不安全
g++ thread_C++.cpp -o thread_C++ -pthread

man帮助手册下载

wget https://mirrors.edge.kernel.org/pub/linux/docs/man-pages/man-pages-5.13.tar.gz

tar -xzvf man-pages-5.13.tar.gz

cd man-pages-5.13

make
make install

多线程与fork

  • fork复制进程中的所有线程(所有资源),但只启用一条执行路径,即:启用fork所在的执行路径(线程)
  • fork,父子进程使用各自的锁,但子进程会复制父进程锁的状态
#include <pthread.h>
//指定fork前后调用的进程
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
//prepare:fork之前执行的程序
//parent:父进程中执行的程序
//child: 子进程中执行的程序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值