天天看点

pthread thread mutex synchronous asynchronous communication

设置进程绑定状态的函数pthread_attr_setscope

pthread_attr_t 指向属性结构的指针

第二个参数 绑定类型 pthread_scope_system()

pthread_scope_process(非绑定)

创建一个绑定线程

线程属性结构

pthread_attr_t

#include <pthread.h>

pthread_attr_t attr;

pthread_t tid;//线程标识符id

//初始化属性值,均设为默认值

//代码创建绑定线程

//初始化线程属性,均设为默认值

pthread_attr_init(&attr);

pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM);设置线程绑定状态函数

pthread_scope_system(绑定)

pthread_scope_process(非绑定的)

pthread_create(&tid,&attr,(void *)my_function,NULL);

线程是否绑定 决定影响线程的响应速度

线程分离状态 决定一个线程以什么样的方式终止

线程分离状态决定线程什么方式终止自己

线程的默认属性 非分离状态

非分离状态下,原有的线程等待创建的线程结束

pthread_join等待线程结束

原有的线程等待创建的线程结束,只有当pthread_join()函数返回 创建的

线程才算结束 才能释放自己占用系统资源

分离线程不是這个样子 没有被其它的线程所等待 分离线程 没有被其它线程等待

自己运行结束了 ,线程 就终止 了

马上释放系统资源

设置线程分离状态函数pthread_attr_setdetachstate(pthread_attr_t *attr,int detachstate);

第二个参数为pthread_attr_setdetachstate()

pthread_create_detached

pthread_create_joinable

如果设置一个线程为分离线程 而线程运行又非常快

很可能此线程在pthread_create函数返回之前就终止了

终止以后就有可能将线程号和系统资源移交给其它的线程使用

這样调用pthread_create的线程就得到了错误的线程号

避免这种情况采取一定的同步措施

在被创建的线程里面调用pthread_cond_timewait

让线程等待一会

留出足够的时间让函数pthread_create返回

设置一段等待时间,是在多线程编程里面常用的方法

不能使用wait() wait使整个进程睡眠,并不能解决线程同步问题

属性 线程优先级priority 存在于结构 sched_param

pthread_attr_getschedparam

pthread_attr_setschedparam

一般来说我们总是先取优先级,对取得值进行修改后再存放回去

线程的属性优先级sched_param

sched.h sched_param

sched_param sched.h

#include <sched.h>

pthread_t tid;

sched_param param;

int newprio = 20;

pthread_attr_init(&attr);//

pthread_attr_getschedparam(&attr,&param);

param.sched_priority = newprio;

pthread_attr_setschedparam(&attr,&param);

pthrea_create(&tid,&attr,(void *)myfunction,myarg);

线程的数据处理

和进程相比 线程的最大优点之一 数据共享性

各个线程共享进程处沿袭的数据段,可以方便的获取,修改数据

线程的数据共享性在带来方便性的同事 也给多线程编程带来了问题

我们必须当心有多个不同的进程访问相同的变量

线程数据处理

线程

函数中

线程中共享的变量必须用关键字volatile定义 防止编译器在 gcc -OX

防止编译器在优化时改变了使用方式

为了保护变量 我们必须使用信号量 signal metux 保证对变量正确使用

线程数据

单线程程序 两种基本数据

global variable local variable;

多线程程序中 第三种数据类型

tsd thread-specific data

和全局变量象

线程内部 各个函数可以像使用全局变量一样调用

为每个线程创建一个建 线程和建相关联

在各个线程路面 都使用這个建来指代线程数据 在不同的线程里

和线程数据相关的函数

创建建 为一个键指定线程数据

从一个键读取线程数据 删除键

volatile 保护变量 使用信号量 互斥 保证我们对变量的正确使用

单线程程序里面 两种基本的数据 全局 变量 局部变量

多线程 有三种 数据类型

线程数据thread_specific da ta

线程数据和全局变量很像

线程内部 各个函数可以像使用全局变量一样调用 对线程外部的其他线程 不可见 数据的必要性

errno

errno 线程变量

线程数据创建建 线程和建相关联在各个线程里都使用键指代线程数据

在不同的线程 键指代的数据不同 在同一个线程里 代表同样的数据

线程数据只在线程内部;

实现线程数据变量 ,需要为每个线程创建键 线程再和建关联

各个线程里都使用键代指线程数据

线程数据相关函数

创建键 为一个键指定线程数据

从键读取线程数据

删除键

创建键函数portable

extern init pthread_key_create __P((pthread_key_t *__key,void (* _destr_function)(void *)))

第一个参数指向一个键值指针

第二个参数

指明了destructor

destructor参数不为空

每当线程结束 系统将调用這个函数释放绑定到键上的内存块

pthread_once((pthread_once_t *once_control,void (*initroutine)(void)))

做到每个线程中数据都是键对应线程的数据 ,各个线程之间的线程数据 是对立的

互斥锁

保证一段时间内只有一个线程执行一段代码

读写程序公用缓冲区

缓冲区只保存一条信息 缓冲区只有两个状态 有信息没信息

void reader_function()

char buffer;

int buffer_has_item=0;

pthread_mutex_t mutex;

struct timespec delay

struct timespec delay;

void main(void)

{

pthread_t reader;

//定义延迟时间

delay.tv_sec = 2;

delay.tv_nec = 0;

}

使用默认属性初始化互斥锁对象

pthread_mutex_init(&mutex,NULL);

pthread_create(&reader,pthread_attr_default,);

条件变量

使用互斥锁实现线程间数据共享和通信

互斥锁明显缺点 只有两种状态

条件变量通过允许线程阻塞和等待另另一个线程发送信号方法弥补互斥锁的不足

条件变量的结构为pthread_cond_t

condition;

pthread_cond_init()用来初始化一个条件变量

extern init pthread_cond_init __p((pthread_cond_t * __cond,__const pthread_cond arrt_t * _ cond attr));

第一个参数指向结构体指针

pthread_cond_t

cond_attr 指向结构体的指针

pthread_condattr_t是条件变量的属性结构 和互斥锁一样我们可以用它来设置条件变量是

pthread_cond_destroy(pthread_cond_t cond)

释放一个条件变量的函数

pthread_cond_wait()使线程阻塞在一个条件变量上

线程解开mutex指向的锁并被条件变量cond阻塞

进程在内存中有3部分

数据段 堆栈段 代码段

代码段

存放程序代码的数据,如果有数个进程运行同一个程序 那么他们就可以使用同一个代码段

数个进程同时运行同一个程序 可以同时使用同一个

堆栈段 存放的是子程序的返回地址

参数以及程序的

参数 程序的局部变量 主要保存进程的执行环境

這里用到了堆栈 先进后出 具有记忆上一次执行环境

数据段:存放程序的全局变量常数;

动态数据分配的数据空间

系统如果同时运行数个相同的程序 他们之间就不能使用同一个堆栈和数据段

函数返回值就是进程数据段所连接的实际地址,共享内存的地址

使用共享存储实现进程间通信注意 对数据存储的同步 必须确保一个进程去°数据 它所想要的数据已经写好了

通信信号量被用来实现对共享存储数据存储的同步;

动态函数库产生的可执行文件比较小,动态函数库在编译的时候

并没有被编译进目标代码

程序执行到相关函数时才调用该函数库相应函数

动态函数所产生的可执行文件比较小 由于函数 没有被整合进你的程序 程序运行时动态申请并调用

所以程序是运行环境中必须提供相应的库 动态函数库的改变 不影响程序,动态函数库的升级比较方便

O0

O

o00O

程序执行到相关函数才调用该函数里的 相关函数 由于函数库没有被整合进你的程序 而是程序运行动态申请调用

程序运行环境提供相应的库

oO0

互斥量

mutex

互斥量 用pthread_mutex_t数据类型表示

两种方式初始化

赋值为常量pthread_mutex_initializer互斥量动态分配

pthread_mutex_init

pthread_mutex_destroy;

int pthread_mutex_init(pthread_mutex_t * __mutex,__const pthread_mutexattr_t *__mutexattr);

int pthread_mutex_destroy(pthread_mutex_t *__mutex);

返回值,成功0

加锁pthread_mutex_lock

解锁pthread_mutex_unlock;

int pthread_mutex_lock(pthread_mutex_t *__mutex);

int pthread_mutex_unlock(pthread_mutex_t *__mutex);

适用于度的次数大于写的情况

int pthread_rwlock_init(pthread_rwlock_t *__restrict __rwlock,__const pthread_rwlockattr_t *__restrict __attr);

int pthread_rwlock_destroy(pthread_rwlock_t *__rwlock);

读加锁

int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock);

写加锁

int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock);

pthread_cond_t数据类型表示,条件变量本身由互斥量保护

condination variables mutex variables 保护 改变条件状态前锁住互斥量

条件变量初始化

赋值常量pthread_cond_initializer;

条件量初始化 两种方式

使用赋值常量pthread_cond_initializer

使用pthread_cond_init函数

int pthread_cond_init(pthread_cond_t *__restrict_cond,__const pthread_condattr_t *__restrict __cond_mutex)

如果一个进程中某一个线程调用了一个阻塞的系统调用,该进程包括该进程中的其他线程同时被阻塞

用户级线程缺点是在一个进程中的多个线程的调度中无法发挥多处理器的优势

核心级

核心级别线程允许不同进程中的线程按照同一相对优先调度方法进行调度

线程允许不同进程中的线程安装同一相对优先调度方法进行调度,发挥多核处理器并发优势

既可以满足多核处理器 也可以最大限度减少调度开销

linux线程核外 核内提供的创建进程的接口do_fork();

内核提供了两个系统调用clone fork

最终都用不同的参数调用do_fork核内API

核内提供的是创建进程的接口

实现线程 没有内核对多进程共享数据段的支持不行 多进程 轻量级进程;

clone_vm共享内存空间

clone_fs 共享文件系统信息

clone_files共享文件描述符表

clone_sighand共享信号句柄表clone_pid共享进程id,仅对核内进程0号进程有效;

使用fork系统调用 内核调用 do_fork()不适应任何共享属性,进程拥有独立的运行环境

使用pthread_create()创建线程 则最终设置了所有这些属性来调用__clone()

参数又全部传个do_fork(),从而创建的进程拥有共享的运行环境

只有

linux线程在核内以轻量级进程的形式存在的,,拥有独立的进程表项

所有创建 sync hronous delete 核外pthread 库

pthRead库使用管理线程__pthread_manager()管理线程 每个进程独立且唯一

来管理线程的创建 为线程分配id 发送线程相关的信号cancal 主线程pthread_create调用则通过 管道将请求信息传个管理线程

绑定属性:linux采用一对一线程机制 也就是一个用户线程对应一个内核线程

绑定属性就是指一个用户线程固定地分配给一个内核线程

一个用户线程固定地分配给一个内核线程

一对一线程机制 一个用户线程对应一个内核线程

绑定属性就是一个用户线程固定地分配给一个内核线程,

cpu时间片段的调度是面向内核线程

而非绑定属性指用户线程和内核线程的关系不是始终固定的,

非绑定属性指用户线程和内核线程的关系不是始终固定的,而是由系统来控制分配的

分离属性

分离属性情况下 一个线程结束立即释放它所占用的系统资源;

所占用的系统资源 没有真正的终止

分离属性用来决定一个线程以什么样的方式终止自己

需要注意的 一点

设置线程分离 线程运行非常快

它很可能在pthread_create线程创建函数返回前就在终止了

终止以后就可能将线程号和系统资源移交给其他的线程使用,这时调用pthread_create

scope

pthread_scope_system

此线程与系统中所有线程竞争

pthread_scope_proces 非绑定,此线程与进程中的其他线程竞争

pthread_scope_system绑定,此线程与系统中所有的线程竞争

int pthread_attr_getdetachstate(const pthread_attr_t *tattr,int *detachstate)

detachstate

int pthread_attr_setschedpolicy(pthread_attr_t *tattr,int policy)

int pthread_attr_getschedpolicy(pthread_attr_t *tattr,int *policy);

设置线程调度策略

policy

sched_fifo 先进先出

sched_rr 循环

sched_other 实现定义的方法

实则优先级

int pthread_attr_setschedparam(pthread_attr_t *attr,struct sched_param *param);

线程访问控制

互斥锁mutex

通过锁机制实现线程间同步synchronous

同时只允许一个线程执行一个关键部分的代码

只允许一个线程执行一个关键部分的代码

int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_T *mutex);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

访问控制 access control;

互斥锁 实现线程间的同步 同时只允许 一个线程执行一个关键部分的代码

初始化锁

静态赋值

pthread_mutex_t mutex = pthread_mutex_initializer initializer;

lock trylock lock

加锁 lock阻塞的等待锁

trylock 立即返回ebusy

解锁unlock需要满足加锁状态,

unlock需要满足是加锁状态,同时由加锁线程解锁

deestroy 清除lock

此时锁必须是unlock

recursive mutex

reentrant

mutex inter-thread同步工具同一线程 可以重复对

Concurrent

reentrantlock

crtical_section

继续阅读