线程基础--线程控制

3.  线程控制

1). 线程属性

目标:可以设置 线程的 detached/join 状态,线程栈的大小和最低地址等属性。

detached/join 状态的区别

当线程处于 分离状态(detached)时,线程结束时,os立即回收资源。主线程不可以调用pthread_join获取线程退出时的返回值。

当线程处于 未分离状态(join)时,线程结束时,主线程 调用pthread_join获取线程退出时的返回值, 随后释放该线程资源。

a)数据类型 pthread_attr_t

b)初始化及释放属性结构 pthread_attr_init  pthread_attr_destroy

初始化时 会分配内存,所以一定要与 _..destroy 函数相对应

c)获取或设置线程分离状态 pthread_attr_setdetachstate      pthread_attr_getdetachstate

有2种可选的状态值:

PTHREAD_CREATE_DETACHED   分离状态

PTHREAD_CREATE_JOINABLE   正常状态,可以使用pthread_join来获取状态

d)应该获取pthread_atr_destroy的返回值,因为使用pthread_attr_init初始化的时候可能分配有内存,如果释放内存失败的话,

会造成内存泄漏

e)控制线程栈的空间的大小

需求:多个线程的栈空间累计超过了进程的可用虚拟地址空间

线程调用函数的自动变量很多,或者递归很深

1)管理stackaddr线程属性,管理stacksize线程属性

pthread_attr_getstack

pthread_attr_setstack

2)获取或设置线程栈的大小

pthread_attr_setstacksize  系统帮助分配内存,自己不用管

pthread_attr_getstacksize

3)线程栈的保护

默认大小为宏PAGESIZE,但修改了栈属性后,这个值就会变成0

pthread_attr_getguardsize

pthread_attr_setguardsize

f)线程属性-并发度

pthread_attr_setconcurency

pthread_attr_getconcurency

2). 同步属性 (线程的同步对象 (例:互斥量、读写锁、条件变量)的属性)

实现同步的3种方式中的对象的属性

a)互斥量属性 pthread_mutexattr_t

1)初始化及释放  pthread_mutexattr_init pthread_mutexattr_destroy

2)进程共享属性

获取与设置共享属性 pthread_mutexattr_getpshared   pthread_mutexattr_setpshared

PTHREAD_PROCESS_PRIVAE 进程内的多个线程可以访问同一个同步对象,默认属性

PTHREAD_PROCESS_SHARED 多个进程可以共享同一块内存区域  内存共享技术。将互斥量用于进程间对同一内存区访问的同步

3)互斥量类型属性

目标:设置 同一线程对已上锁的互斥量再次上锁 是否 死锁等属性。

PTHREAD_MUTEX_NORMAL   标准的互斥量类型,不做错误检查或死锁检查

PTHREAD_MUTEX_DEFAULT  依赖于操作系统提供到其他类型的映射

PTHREAD_MUTEX_ERRORCHECK 提供错误检查

PTHREAD_MUTEX_RECURSIVE (递归锁)允许多次加锁,但是需要解锁对应次数 tmd,这个类型叫做递归锁

获取与设置互斥量类型属性

pthread_mutexattr_gettype  pthread_mutexattr_settype

应用场景:

PTHREAD_MUTEX_RECURSIVE (递归锁)
当将现有的单线程接口放到多线程环境中时,使用递归锁

例:

同一线程中 func1、 func2分别对 互斥量加锁, 若不是用 递归锁则会出现死锁。

b)读写锁属性 pthread_rwlockattr_t

可以设置是否支持进程共享属性 (默认为 只支持 线程共享属性 )

c)条件变量属性pthread_condattr_t

可以设置是否支持进程共享属性 (默认为 只支持 线程共享属性

4. 线程重入

可重入函数--指在信号处理函数中,正在执行的程序被信号处理程序中断后,返回时 不能正确运行的函数。

原因:(a)使用了静态数据结构--全局的,会被其他线程/信号处理函数 等 使用

(b)调用了 malloc / free ( malloc 为它所分配的存储区维护一个链接表,执行信号处理函数时,进程可能正在修改

该表,导致被破环)

(c)标准I/O函数--大部分使用了 全局结构变量

1)线程安全:如果一个函数同一时刻可以被多个线程安全地调用

2)系统是否支持线程安全函数  sysconf(_POSIX_THREAD_SAFE_FUNCTIONS)

非线程安全的原因:返回的数据存放在静态的内存缓存区,多个线程调用该函数的时候 会覆盖前面正在使用的区域。

将其进行可重入,为其分配自己的缓存器,避免被其他线程干扰,可以保证是线程安全的。

重入后的函数,成为线程安全,并不意味着 它对信号处理程序是可重入的。(请举例,不太懂??)

3)异步-信号安全:如果函数对异步信号处理程序的重入是安全的

4)锁文件的3个函数

flockfile  ftrylockfile   funlockfile

该锁是递归锁

5)确保函数在进程里面只被调用一次

pthread_once_t var = PTHREAD_ONCE_INIT;

pthread_once(&var, function);

5. 线程私有数据

一种 让存储和查询 数据 与 某个线程相关的 机制。避免 与其他线程 同步访问的问题

1)需要的数据类型: pthread_key_t

2)创建私有数据的步骤

pthread_key_t key;

a)pthread_key_create(&key, 清理函数地址) 一般通过pthread_once确保函数只被执行一次,变量只被初始化一次

b)char* addr = pthread_getspecific(&key)

c)为addr分配内存 malloc

d)pthread_setspecific(&key, addr);

e)pthread_key_delete删除key

f)线程退出,执行清理函数地址

6.  线程取消

设置pthread_cancle 函数相关的属性项

1)线程可以被设置为是否可取消

pthread_setcancelstate(int state, int* oldstate)

2)pthread_cancel只是一个申请,只有线程到达了取消点才会取消.

3)延迟取消pthread_testcancel, 适合于没有取消点的函数

4)设置取消的类型pthread_setcanceltype

7.  线程与IO

pread,pwrite 原子io操作

例:

线程A

lseek( fd, 300, SEEK_SET);

read( fd, buf1, 100);

线程B

lseek( fd, 700, SEEK_SET);

read( fd, buf2, 100);

当 A执行完lseek,B在A调用read之前调用lseek, 最后 两线程 读取同一条记录 (对同一文件操作,后一个 偏移量设置 覆盖了前一个设置)。

解决方法:

pread--将偏移量设定和数据读取成为一个原子操作

线程A

pread( fd, buf1, 100, 300);

线程B

pread( fd, buf2, 100, 700);

8.  线程与信号

每个线程有自己的信号屏蔽字,但是他们共享

1)相同的信号处理函数 2)该信号与某函数的绑定,一个信号绑定到某个函数,这个被所有线程共享, 他们只能看到一个

多个线程公用进程的信号屏蔽机制,除了2种情况以外:

硬件故障的信号与计时器超时的信号,只递送给某个线程,其它的信号会发送给所有线程

pthread_sigmask

sigwait 等待信号发送.  一般操作需要先阻塞信号,sigwait调用会取消信号的阻塞状态,直到新信号到来

pthread_kill

sigwait(sigset_t*, int* signo)

sigwait的参数2表示捕获到的信号值

9.  线程与fork

pthread_atfork,理论内容相当多,过滤掉

当线程调用fork时,就会为子进程创建整个进程空间的副本。包括从父进程继承的互斥量、读写锁和条件变量等。

因此,如果父进程包含多个线程,子进程在fork返回后,没有调用exec (原来的地址空间会被丢弃)的话,就需要清理锁状态。

pthread_atfork( void (*prepare)(void), void (*parent)(void),void
(*child)(void));

可以设置3个锁清理函数。

prepare fork 由父进程 在fork创建子进程前调用,任务:获取父进程定义的所有锁。

parent fork: fork创建子进程后,但在fork返回之前,在父进程中 调用。

child fork :fork创建子进程后,但在fork返回之前,在子进程中 调用。

10.  同一进程的所有线程共享同一个计时器

11.  同一进程的所有线程共享相同的文件描述符

线程基础--线程控制,布布扣,bubuko.com

时间: 2024-11-18 18:51:52

线程基础--线程控制的相关文章

线程基础知识

什么是线程: 在一个程序里的一个执行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列" 一切进程至少都有一个执行线程 进程与线程 进程是资源竞争的基本单位 线程是程序执行的最小单位 线程共享进程数据,但也拥有自己的一部分数据 线程ID 一组寄存器 栈 errno 信号状态 优先级 fork和创建新线程的区别 当一个进程执行一个fork调用的时候,会创建出进程的一个新拷贝,新进程将拥有它自己的变量和它自己的PID.这个新进程的运行时间是独立的,它在执行时几乎

线程基础:线程池(6)——基本使用(中)

(接上文:<线程基础:线程池(5)--基本使用(上)>) 3-4.JAVA主要线程池的继承结构 我们先来总结一下上文中讨论过的内容,首先就是JAVA中ThreadPoolExecutor类的继承结构.如下图所示: ThreadPoolExecutor:这个线程池就是我们这两篇文章中介绍的重点线程池实现.程序员可以通过这个线程池中的submit()方法或者execute()方法,执行所有实现了Runnable接口或者Callable接口的任务:ThreadPoolExecutor对于这些任务的执

Java基础——线程总结

Java基础--线程总结 一.线程是什么? 线程:一个程序里不同的执行路径. 二.如何创建线程? 两种方法创建线程: 第一种 (1)定义具体功能类实现Runnable接口,可以多次调用而实现数据共享 (2)Thread myThread = new Thread(-)          //参数为Runnable接口类型 (3)Runnable中只有一个方法 public void run(){--} //用以定义线程运行体 第二种 (1)定义一个Thread的子类并重写run()方法 clas

操作系统核心原理-4.线程原理(上)线程基础与线程同步

我们都知道,进程是运转中的程序,是为了在CPU上实现多道编程而发明的一个概念.但是进程在一个时间只能干一件事情,如果想要同时干两件或者多件事情,例如同时看两场电影,我们自然会想到传说中的分身术,就像孙悟空那样可以变出多个真身.虽然我们在现实中无法分身,但进程却可以办到,办法就是线程.线程就是我们为了让一个进程能够同时干多件事情而发明的“分身术”. 一.线程基础 1.1 线程概念 线程是进程的“分身”,是进程里的一个执行上下文或执行序列.of course,一个进程可以同时拥有多个执行序列.这就像

Qt 线程基础(QThread、QtConcurrent等) 2

使用线程 基本上有种使用线程的场合: 通过利用处理器的多个核使处理速度更快. 为保持GUI线程或其他高实时性线程的响应,将耗时的操作或阻塞的调用移到其他线程. 何时使用其他技术替代线程 开发人员使用线程时需要非常小心.启动线程是很容易的,但确保所有共享数据保持一致很难.遇到问题往往很难解决,这是由于在一段时间内它可能只出现一次或只在特定的硬件配置下出现.在创建线程来解决某些问题之前,应该考虑一些替代的技术 : 替代技术 注解 QEventLoop::processEvents() 在一个耗时的计

线程基础知识系列(三)线程的同步

本文是系列的第三篇,前面2篇,主要是针对单个线程如何管理,启动等,没有过多涉及多个线程是如何协同工作的. 线程基础知识系列(二)线程的管理 :线程的状态,控制,休眠,Interrupt,yield等 线程基础知识系列(一)线程的创建和启动  :线程的创建和启动,join(),daemon线程,Callable任务. 本文的主要内容 何谓线程安全? 何谓共享可变变量? 认识synchronized关键字 认识Lock synchronized vs Lock 1.何谓线程安全 多线程是把双刃剑,带

线程基础:JDK1.5+(8)——线程新特性(上)

1.概要 如果您阅读JAVA的源代码,出现最多的代码作者包括:Doug Lea.Mark Reinhold.Josh Bloch.Arthur van Hoff.Neal Gafter.Pavani Diwanji等等.其中java.util.concurrent包中出现的基本都是Doug Lea的名字.Doug Lea,是对Java影响力最大的个人,直接贡献的设计包括java的Collections和util.concurrent. JDK1.5中一个重要特性就是util.concurrent

第6章 线程基础

6.1 线程基础 (1)线程组成:线程内核对象+线程栈(注意:进程=进程内核对象+地址空间) ①从内核角度看,线程是一个内核对象,系统用它来存储一些关于线程的统计信息(比如运行时间等) ②从编程角度看,线程是一堆寄存器状态以及线程栈的一个结构体对象.本质上可以理解为一个函数的调用器(其中的寄存器状态用于控制CPU执行,栈用于存储局部变量和函数参数及函数的返回地址)——为什么要使用线程栈的? 线程1 线程2 备注(使用线程栈的原因分析) void func1(){ int a; int b; }

线程基础--同步机制 (1)

1.  线程基础    概念 1). 线程全称控制线程 2). 多线程的优势: a) 比进程方便,可以共享相同的内存空间及文件描述符 b) 可以用于多个任务,而这些任务如果用单进程来实现是串行,在多线程里面由于CPU的调度可以实现穿插执行 c) 用于交互程序,将用户输入输出与其他部分分开,优化性能 3). 如何知道系统是否多线程pthread(POSIX线程) a) #ifdef  _POSIX_THREADS b) sysconf(_SC_THREADS) 4). 一个线程的数据结构 线程ID