OK,这个就是pthread_cond_wait()的原理了,只不过它把continue变成了"休眠"这种由OS负责的操作,可以大大的节约资源。
当然,线程执行的条件是很难当作参数传入一个函数的,POSIX多线程的模型使用系统提供的"条件变量"+"我们自己定义的具体条件" 来确定一个线程是否应该执行接下来的内容。"条件变量"只有真和假,所以一种典型的多线程同步的结构如下
//线程B,出队
while(
1){
lock(mutex);
while(条件不满足)
pthread_cond_wait(cond,mutex)
//获得互斥锁可以同时保护while里的条件和cond的判断,二者总是用一把锁保护,并一同释放
//cond为假,就休眠同时释放锁,等待被cond为真唤醒,把自己获得的锁拿回来
//拿回自己的锁再检查线程执行条件,条件不满足继续循环,直到条件满足跳出循环
//这个函数是带着"线程的执行条件为真"+"cond为真"走出循环的
//这个函数返回后cond被重新设置为0
out_queue(Q);
unlock(mutex);
}
pthread_cond_braoadcast()/pthread_cond_signal()
//使条件变量为真并唤醒wait中的线程,前者唤醒所有wait的,后者唤醒一个
//成功返回0,失败返回error number
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_destroy()
//销毁条件变量
//成功返回0,失败返回error number
int pthread_cond_destroy(pthread_cond_t *cond);
例子-线程池
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//thread.h
#ifndef __THREAD_H__
#define __THREAD_H__
#define THREAD_NUM 3
#define TASK_NUM 100
typedef struct{
//每个节点的封装格式,fcn是用户自定义函数,arg是用户自定义函数参数指针,保证通用性声明为void
void* (*fcn)(void* arg);
void* arg;
}task_t;
typedef struct{
//用户自定义函数的参数结构体
int x;
}argfcn_t;
//#define LQ_DATA_T task_t*
#define LQ_DATA_T task_t
#endif //__THREAD_H__
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//lqueue.c
#include"thread.h"
#include"lqueue.h"
#include<stdlib.h>
...
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//thread_pool.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include"thread.h"
#include"lqueue.h"
//互斥量和条件变量
pthread_mutex_t lock;
pthread_cond_t cond;
//全局的表
lqueue_t* Q;
//每个线程的任务,必须是这个形式的函数指针
void* do_task(void* p){
task_t data;
int ret=
0;
while(
1){
pthread_mutex_lock(
&lock);
while(is_empty_lqueue(Q)){
//大家收到广播,因为延迟,可能醒了好几个,要判断一下是不是自己
pthread_cond_wait(
&cond,
&lock);
//先抢到锁再醒
}
ret=out_lqueue(Q,
&data);
pthread_mutex_unlock(
&lock);
data.fcn(data.arg);
}
}
//创建线程池
void create_pool(void){
//初始化队列
Q=create_lqueue();
//初始化互斥量
pthread_mutex_init(
&lock,NULL);
//初始化条件变量
pthread_cond_init(
&cond,NULL);
int i=THREAD_NUM;
pthread_t tid[THREAD_NUM];
while(i--)
pthread_create(
&tid[i],NULL,do_task,NULL);
}
//准备函数
void* fcn(void* parg){
//用户自定义的需要线程执行的函数
argfcn_t* i=(argfcn_t*)parg;
printf(
"this is task1\n");
printf(
"task1:%d\n",i->x);
}
//添加任务
void pool_add_task(void*(*pfcn)(void*parg),void*arg){
task_t task;
task.fcn=pfcn;
task.arg=arg;
in_lqueue(Q,task);
pthread_cond_signal(
&cond);
//添加了一个任务,用signal更好
}
int main(int argc, const char *argv[])
{
//创建线程池
create_pool();
//准备参数
argfcn_t argfcn;
argfcn.x=
5;
//添加任务
pool_add_task(fcn,(void*)
&argfcn);
pool_add_task(fcn,(void*)
&argfcn);
pool_add_task(fcn,(void*)
&argfcn);
pause();
return
0;
}