函数说明:
线程
int pthread_create(pthread_t restrict tidp, const pthread_attr_t restrict attr, void (start_rtn)(void ), void restrict arg);
int pthread_exit(void rval_ptr);
int pthread_join(pthread_t thread, void *rval_ptr);
pthread_t pthread_self(void);//获取线程ID
互斥锁
int pthread_mutex_init(pthread_mutex_t restrict mutex, const pthread_mutexattr_t restrict attr);
int pthread_mutex_destroy(pthread_mutex_t mutex);
int pthread_mutex_lock(pthread_mutex_t mutex);
int pthread_mutex_trylock(pthread_mutex_t mutex);
int pthread_mutex_unlock(pthread_mutex_t mutex);
条件变量
int pthread_cond_init(pthread_cond_t restrict cond, const pthread_condattr_t restrict attr);
int pthread_cond_destroy(pthread_cond_t cond);
int pthread_cond_wait(pthread_cond_t restrict cond, pthread_mutex_t restrict mutex);
int pthread_cond_timedwait(pthread_cond_t restrict cond, pthread_mutex_t restrict mutex, cond struct timespec *restrict timeout);
int pthread_cond_broadcast(pthread_cond_t cond);
int pthread_cond_signal(pthread_cond_t cond);
信号量强调的是线程或者进程之间的同步,条件变量和互斥锁是对不同线程的代码访问同一段内存区域的控制。信号量只要不为零就可以down
条件变量和互斥锁的区别
- 互斥锁必须是谁上锁就由谁来解锁,而信号量的wait和post操作不必由同一个线程执行。
- 互斥锁要么被锁住,要么被解开,和二值信号量类似
- sem_post是各种同步技巧中,唯一一个能在信号处理程序中安全调用的函数
- 互斥锁是为上锁而优化的;条件变量是为等待而优化的; 信号量既可用于上锁,也可用于等待,因此会有更多的开销和更高的复杂性
- 互斥锁,条件变量都只用于同一个进程的各线程间,而信号量(有名信号量)可用于不同进程间的同步。当信号量用于进程间同步时,要求信号量建立在共享内存区。
- 信号量有计数值,每次信号量post操作都会被记录,而条件变量在发送信号时,如果没有线程在等待该条件变量,那么信号将丢失。
对互斥锁mutex的介绍
include
int pthread_mutex_init(pthread_mutex_t *mutex, const phread_mutexattr_t mutexattr );
//mutex指向要操作的目标锁,pthread_mutex_t是一个结构体
//mutexattr指明互斥锁的属性,NULL表明使用默认属性,默认属性下是普通锁
//当一个线程对普通锁加锁之后,其余请求该锁的线程将形成一个等待队列,并在该锁被解锁是按优先级获得它
问题:一个线程对一个已经加锁的普通锁加锁,将引发死锁
一个已经解锁的普通锁再次解锁,将导致不可预期的后果
条件变量:用在线程之间同步共享数据的值,条件变量提供了一种机制,当共享数据达到某个值的时候,
唤醒等待这个共享数据的线程
pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* cond_attr);
第一个参数cond指向将要操作的目标条件变量,条件变量类型是pthread_cond_t结构体
cond_attr指定条件变量的属性。如果设置为NULL表示使用默认时薪
*/
//创建互斥量cond:
//
//pthread_cond_t cond = PTHREAD_COND_INITIALIZER
//
//还可以通过函数的方式创建:
//
//int pthread_cond_init(pthread_cond_t * cond, NULL);
//
//注意:两种方式创建有所区别,第一种是创建静态全局的,所创建的量在全局区,
//第二种创建的量在栈,两种的区别我们可以理解为全局变量和局部变量的差异,
//如果创建的是全局的条件量则用第一种方式初始化,如果是在函数内部创建则用第二种方式。
//这里其实跟互斥锁一样,互斥锁也可以用这两种方式初始化,原理相同。
//int pthreadcond_destroy(pthread_cond_t* cond);
//
//注意:只有在没有线程使用该互斥量的时候才能销毁,否则会返回EBUSY。
//
//等待:
//
//当线程不满足给定条件时,让线程挂起,挂起分为两种,一种是无限制的等待,pthread_cond_wait;
//一种是定时等待,pthread_cond_timedwait。无论是哪种等待都必须和锁配合使用
//,防止多个线程同时使用互斥量。
//
//注意两个函数
//
//pthread_cond_wait(pthread_cond_t cond, pthreadmutex_t mutex);
//
//pthreadcond_timedwait(pthread_cond_t cond, pthreadmutex_t mutex, const struct timespec time);
//
//
//唤醒:
//
//当线程满足某个条件时,可以唤醒被挂起的线程,唤醒有两个函数
//
//一是唤醒等待该互斥量的线程:
//
//pthread_cond_signal(pthread_cond_t cond);
//
//二是唤醒所有等待线程:
//pthread_cond_broadcast(pthread_cond_t* cond);
//void pthread_exit(void* retval);
//通过retval参数想线程的回收者传递其退出信息,该函数执行完毕之后不会返回到调用者,而且永远不会失败。
线程
创建新线程的函数:
int pthreadcreate(pthread_t thread, const pthreadattr_t arr,
void ( _start_routine)(void), void_ arg);
thread参数是新线程的标识符
arr == NULL表示使用默认新线程属性
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。
C++11线程睡眠的方式
std::this_thread::sleep_for(std::chrono::seconds(3)); //休眠三秒
std::this_thread::sleep_for(std::chrono:: milliseconds (100)); //休眠100毫秒
一个线程池包括以下四个基本组成部分:
(1)、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
(2)、工作线程(WorkThread):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
(3)、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
(4)、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。