一、线程的基本概念和用法
https://blog.csdn.net/zgege/article/details/79912418
二、线程的同步
https://blog.csdn.net/zgege/article/details/79992333
线程同步的机制包括:互斥锁,读写锁,自旋锁,条件变量,信号量,异步信号
读写锁:
读写锁与互斥量类似,不过读写锁允许更高的并行性。适用于读的次数大于写的次数的数据结构。
一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁
自旋锁:
互斥量阻塞线程的方式是使其进入睡眠,而自旋锁是让线程忙等,即不会使其睡眠,而是不断循判断自旋锁已经被解锁。
适用于占用自旋锁时间比较短的情况。
条件变量:
给多个线程提供一个会合的场所,条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定条件的发生;
信号量和异步信号:
http://www.cnblogs.com/wanghuaijun/p/9532644.html
介绍一下POSIX(POSIX标准定义了操作系统应该为应用程序提供的接口标准,换句话说,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。)的信号量机制,定义在头文件/usr/include/semaphore.h
1)初始化一个信号量:sem_init()
int sem_init(sem_t* sem,int pshared,unsigned int value);
pshared为0时表示该信号量只能在当前进程的线程间共享,否则可以进程间共享,value给出了信号量的初始值。
2)阻塞线程
sem_wait(sem_t* sem)直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少;sem_trywait(sem_t* sem)是wait的非阻塞版本,它直接将sem的值减一,相当于P操作。
3)增加信号量的值,唤醒线程
sem_post(sem_t* sem)会使已经被阻塞的线程其中的一个线程不再阻塞,选择机制同样是由线程的调度策略决定的。相当于V操作。
3)释放信号量资源
sem_destroy(sem_t* sem)用来释放信号量sem所占有的资源
pthread_mutex_t mutex; sem_t full,empty; void producer(void* arg){ while(1){ sem_wait(&empty);//need to produce. the the empty of resource need minus 1 pthread_mutex_lock(&mutex); ...//produce a resource pthread_mutex_unlock(&mutex); sem_post(&full); //have produced a resource, the the full of resource need add 1 } } void consumer(void* arg){ while(1){ sem_wait(&full); pthread_mutex_lock(&mutex); ...//consume a resource pthread_mutex_unlock(&mutex); sem_post(&empty); } }
三、线程的属性
属性的初始化以及销毁
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
detachstate属性的分离状态:
如果对某个线程的终止状态不感兴趣的话,可以使用pthread_detach函数将操作系统在线程退出时回收
它所占用的资源;
detachstate有两个合法值:
PTHREAD_CREATE_DETACHED以分离状态启动线程;
PTHREAD_CREATE_JOINABLE正常启动线程;
int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr, int *detachstate);
int pthread_attr_setdetachstate(const pthread_attr_t *attr, int *detachstate);
stacksize属性:
如果希望改变默认栈的大小,又不想自己处理线程栈的分配问题,这时使用pthread_attr_setstacksize函数非常有用;
int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
stackaddr属性:
- 对于进程来说,虚拟地址的大小是固定的,因为进程中只有一个栈,所以它的大小通常不是问题;但对于线程来说,同样大小的虚拟地址空间必须被所有的线程栈共享,如果应用程序使用了很多线程,以至于这些线程栈的累计大小超过了可用的虚拟地址空间,就需要减小默认的线程栈的大小;
- 栈消耗较大的两种情况:线程调用的函数分配了大量的自动变量、调用的函数涉及很深的栈帧;
- 如果线程的虚拟地址空间用完了,可以使用malloc或者mmap来为替代的栈分配空间;
int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, size_t *restrict guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
guardsize属性:
控制着线程栈末尾之后用以避免栈溢出的扩展内存的大小;
int pthread_attr_getstack(const pthread_attr_t *restrict attr, void **restrict stackaddr, size_t *restrict stacksize);
int pthread_attr_setstack(const pthread_attr_t *attr, void *stackaddr, size_t stacksize);