线程通信和线程属性

线程通信
  线程间的通信⽬的主要是⽤于线程同步。所以线程没有像进程通信中的⽤于数据交换的通信机制。
同⼀进程的不同线程共享同⼀份内存区域,所以线程之间可以⽅便、快速地共享信息。只需要将数据复制到共享
(全局或堆)变量中即可。但是需要避免出现多个线程试图同时修改同⼀份信息
 
 
线程属性
1、线程属性初始化和销毁
#include <pthread.h>
/**
* 初始化线程属性函数,注意:应先初始化线程属性,再pthread_create创建线程.
* @param attr 线程属性结构体.
* @return 成功: 0; 失败: 错误号.
*/
int pthread_attr_init(pthread_attr_t *attr);
/**
* 销毁线程属性所占⽤的资源函数.
* @param attr 线程属性结构体.
* @return 成功: 0; 失败: 错误号.
*/
int pthread_attr_destroy(pthread_attr_t *attr);
2、线程分离状态
(1)⾮分离状态:
线程的默认属性是⾮分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,
创建的线程才算终⽌,才能释放⾃⼰占⽤的系统资源。
(2)分离状态:
分离线程没有被其他的线程所等待,⾃⼰运⾏结束了,线程也就终⽌了,马上释放系统资源。应该根据⾃⼰的需
要,选择适当的分离状态。
注意:
1. 如果设置⼀个线程为分离线程,⽽这个线程运⾏又⾮常快,它很可能在pthread_create函数返回之前就终⽌了,
它终⽌以后就可能将线程号和系统资源移交给其他的线程使⽤,这样调⽤pthread_create的线程就得到了错误的
线程号。
2. 要避免这种情况可以采取⼀定的同步措施,最简单的⽅法之⼀是可以在被创建的线程⾥调⽤
pthread_cond_timedwait函数,让这个线程等待⼀会⼉,留出⾜够的时间让函数pthread_create返回。
#include <pthread.h>
/**
* 设置线程分离状态.
* @param attr 已初始化的线程属性.
* @detachstate(分离状态)
* 1. PTHREAD_CREATE_DETACHED(分离线程);
* 2. PTHREAD_CREATE_JOINABLE(⾮分离线程).
* @return 成功: 0; 失败: ⾮0.
*/
/**
* 获取线程分离状态.
* @param attr 已初始化的线程属性.
* @detachstate(分离状态)
* 1. PTHREAD_CREATE_DETACHED(分离线程);
* 2. PTHREAD_CREATE_JOINABLE(⾮分离线程).
* @return 成功: 0; 失败: ⾮0.
*/
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
3、线程栈地址
当进程栈地址空间不够⽤时,指定新建线程使⽤由malloc分配的空间作为⾃⼰的栈空间。通过pthread_attr_setstack和pthread_attr_getstack两个函数分别设置和获取线程的栈地址。
#include <pthread.h>
/**
* 设置线程的栈地址.
* @param attr 指向⼀个线程属性的指针.
* @param stackaddr 内存⾸地址.
* @param stacksize 返回线程的堆栈⼤⼩.
* @return 成功: 0; 失败: 错误号.
*/
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
/**
* 获取线程的栈地址.
* @param attr 指向⼀个线程属性的指针.
* @param stackaddr 返回获取的栈地址.
* @param stacksize 返回获取的栈⼤⼩.
* @return 成功: 0; 失败: 错误号.
*/
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t
*stacksize);-
4、线程栈⼤⼩
#include <pthread.h>
/**
* 设置线程的栈⼤⼩.
* @param attr 指向⼀个线程属性的指针.
* @param stacksize 线程的堆栈⼤⼩.
* @return 成功: 0; 失败: 错误号.
*/
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
/**
* 获取线程的栈⼤⼩.
* @param attr 指向⼀个线程属性的指针.
* @param stacksize 返回线程的堆栈⼤⼩.
* @return 成功: 0; 失败: 错误号.
*/
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
5、线程使⽤注意事项
(1)主线程退出其他线程不退出,主线程应调⽤pthread_exit
(2)避免僵⼫线程
1. pthread_join
2. pthread_detach
3. pthread_create指定分离属性
被join线程可能在join函数返回前就释放完⾃⼰的所有内存资源,所以不应当返回被回收线程栈中的值(3)malloc和mmap申请的内存可以被其他线程释放
(4)应避免在多线程模型中调⽤fork,除⾮马上exec,⼦进程中只有调⽤fork的线程存在,其他线程t在⼦进程中均
pthread_exit
(5)信号的复杂语义很难和多线程共存,应避免在多线程引⼊信号机制
(6)Cache伪共享:
这种因为多个线程同时读写同⼀个 Cache Line 的不同变量时,⽽导致 CPU Cache 失效的现象。避免的⽅式⼀般有
Cache Line ⼤⼩字节对齐,以及字节填充等⽅法。在 Linux 内核中存在cachelinealignedin_smp 宏定义,是⽤于解
决伪共享的问题。
posted @ 2023-08-31 15:28  好像流沙  阅读(8)  评论(0编辑  收藏  举报