pthread 为POSIX线程库,windows和linux皆可用。
//例子来源教材,百度文库,以及csdn blog
1. 路径为/lib/x86_64-linux-gnu/, libpthread-2.15.so
这些lib 有不同的颜色。颜色的区别是什么?
libpci.so.3.1.8 和libpci.so.3 的区别是什么?
颜色不同,代表文件类型不同。用ll 查看。
-代表普通文件,白色
l代表软链接文件,蓝色
还有绿色,代表具有可执行权限
关于蓝色软链接,以及lib*.so.*后面的数字,代表版本号。
当安装软件时,如果安装了这些同类库,但是版本不同,如果高版本可以兼容旧版本,则创建一个旧版本的软链接 ,不再创建新文件。
2. 线程的概念
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
一个进程是一个复合的实体,可以分为两个部分:线程集合 + 资源集合。
使用多线程一般有两个不同的目的:
一是把程序细分成几个功能相对独立的模块,防止其中一个功能模块阻塞导致整个程序假死(GUI程序是典型)(多任务)
另一个就是提高运行效率,比如多个核同时跑,或者单核里面,某个线程进行IO操作时,另一个线程可以同时执行(并发)。
posix pthread 库
// 创建线程
#include <pthread.h>
int pthreat_t pthread_creat(pthread_t *thread,pthread_attr_t * attr,void *(*start_routine)(void *),void *arg)
//typedef unsigned long int pthread_t
//void * arg 用来向*start_routine 传参
//pthread_attr_t attr 指定线程属性,可以默认为NULL
//执行成功返回0,失败返回非零值。
//获得线程id
pthread_t pthread_self(); //无线,线程内部使用
//退出
1 调用函数执行结束后自动退出
2 使用函数退出
void pthread_exit(void* retval) // 在想中途退出时,有用。成功返回0,失败-1。 返回值保存在retval 指针中。
demo1.cpp
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void* say_hello(void* args)
{
cout << "___HELLO___ "<< endl;
pthread_exit(0);
}
int main()
{
pthread_t tids[NUM_THREADS];
for(int i = 0; i < NUM_THREADS; i++)
{
int ret = pthread_create(&tids[i],NULL,say_hello,(void *)&i);
if(ret != 0)
{
cout << "Pthread create error !!!!"<< i <<"____"<< ret << endl;
}
else
{
cout << "main___"<< endl;
}
}
pthread_exit(NULL);////等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过
来;
}
// g++ -o 1 1.cpp -lpthread #此处-l指定库要放在后面,放在-o前面,会说ld 链接错误!! gcc g++ 这是个使用细节。
运行结果:
main___
main___
main___
main___
main___
___HELLO___
___HELLO___
___HELLO___
___HELLO___
___HELLO___
————————结果表明,主线程运行的速度远远比线程速度快多了。并且新线程和主线程是并发的。
demo2.c
#include <pthread.h>
#include <stdio.h>
void print_msg(char *ptr)
{
int retval;
printf("Thread_id is %lx______%s\n",pthread_self(),ptr);
pthread_exit(&retval);
}
/*或者
void print_msg(void *ptr)
{
int retval;
printf("Thread_id is %lx______%s\n",pthread_self(),(char*)ptr);
pthread_exit(&retval);
}
*/
int main()
{
pthread_t thread1,thread2;
char* msg1= "Hello ";
char* msg2 = "WORLD ";
printf("Let's go \n");
pthread_create(&thread1,NULL,(void*)(&print_msg),(void *)msg1);
pthread_create(&thread2,NULL,(void*)(&print_msg),(void* )msg2);
// 线程传参
sleep(2);
return 0;
}
运行结果:
Let's go
Thread_id is 7fb19a42f700______WORLD
Thread_id is 7fb19ac30700______Hello
——————————2个新线程的执行顺序是反的,什么鬼!!
demo3.cpp 线程如何调用类中函数——static
#include <iostream>
#include <pthread.h>
using namespace std;
class hello
{
public:
static void* sayhello(void* args) //static
{
cout << "hello class..."<< endl;
}
};
int main()
{
pthread_t pid[5];
for(int i =0; i < 5; i++)
{
int ret = pthread_create(&pid[i],NULL,hello::sayhello,NULL);
if(ret != 0)
cout << "Pthread_create failed .."<< endl;
}
pthread_exit(NULL);////等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过
来;
return 0;
}
demo3.cpp 线程退出状态和线程属性
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void* say_hello(void* args)
{
cout << "___HELLO___ "<< *((int*)args) << endl;
int status = 10 + *((int*)args); // 将参数+10
pthread_exit((void*)status);//由于线程创建时提供了Jointable参数,这里可以在退出时添加退出信息;
//status提供给主程序提取该线程退出线程的结束信息
}
int main()
{
pthread_t tids[NUM_THREADS];
int indexs[NUM_THREADS];
pthread_attr_t attr;//第一步声明:线程属性,用于pthread_create创建时加入参数
pthread_attr_init(&attr);//第二部:线程属性初始化
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
//第三步:设置你要执行线程属性参数,该参数表明该线程是可以Join连接的,
//join 表示主程序可以等线程结束后再执行,实现了**主程序和线程同步功能**
for(int i = 0; i < NUM_THREADS; i++)
{
indexs[i]= i;
int ret = pthread_create(&tids[i],NULL,say_hello,(void *)&(indexs[i]));//4 arguments
if(ret != 0)
{
cout << "Pthread create error !!!!"<< i <<"____"<< ret << endl;
}
else
{
cout << "main___"<< endl;
}
}
pthread_attr_destroy(&attr); //创建线程后,该参数已经结束使命,必须销毁,防止内存泄漏。
void* status;
for(int i =0;i< NUM_THREADS;i++)
{
int ret = pthread_join(tids[i],&status);//前面创建了线程,这里主程序想要join 每个线程,然后取得每个线程的退出信息status.
if(ret !=0)
cout << "pthread_join_error: error code : "<< ret << endl;
else
cout << "pthread_join get status: " << (long )status << endl;
}
pthread_exit(NULL);
}
运行结果
main___
main___
main___
main___
main___
___HELLO___ 4
___HELLO___ 3
___HELLO___ 2
___HELLO___ 1
___HELLO___ 0
pthread_join get status: 10
pthread_join get status: 11
pthread_join get status: 12
pthread_join get status: 13
pthread_join get status: 14
——————————线程执行顺序依然是反的!
——————————主程序第一,然后是线程回调,最后是join 部分代码(主程序)(这一部分顺序确是对的,首先创建的线程遍历。)。
- joinable 和 detached 可结合 和 分离的
任何一个时间点,线程是可结合的joinable 或者分离的 detached. 线程的默认状态是非分离状态(即Joinable,需要回收)
Joinable:
能够被其他线程收回资源和杀死
在被其他线程回收前,它的存储器资源(如栈)是不释放的。
detached:
不能被其他线程回收或者杀死
它的存储器资源在它终止时由系统自动释放
可结合线程(Joinable):
线程的**分离状态**决定一个线程以什么样的方式来终止自己。
默认线程我们采用了线程非分离状态(即可结合的,joinable,需要回收)
这种情况下,原有的线程等待创建的线程结束;**只有当pthread_join()函数返回时,创建的线程才算终止**,**才能释放自己占用的系统资源**。
主线程需要**明确执行等待**操作,在子线程结束后,主线程的等待操作执行完毕,子线程和主线程会合,这时主线程继续执行等待操作之后的下一步操作。
分离线程(detached):
分离线程不是这样子的,它没有被其他的线程所等待。
自己运行结束了,线程也就终止了,马上释放系统资源。
线程的分离状态设置
函数 pthread_attr_setdetachstate(pthread_attr_t* attr, int detachstate)
第二个参数值选项为宏PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)
注意点:
如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在 pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用 pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。
如果创建Joinable 线程,那就在主程序中必须pthread_join() 进行资源回收。
#include <pthread.h>
void pthread_exit(void *retval);
void pthread_join(pthread_t th,void **thread_return);//主线程挂起等待th结束
//*thread_return=retval; 新线程结束返回状态,传给*thread_return
int pthread_detach(pthread_t th);
join()挂起
#include <pthread.h>
#include <stdio.h>
void print_msg(char *ptr){
int i;
for( i = 0; i < 10; i++)
printf("_%s_",ptr);
}
int main()
{
pthread_t thread1,thread2;
int i ,j;
void* retval;
char* msg1= " Hello ";
char* msg2 = " WORLD ";
printf("****Let's go*** \n");
pthread_create(&thread1,NULL,(void*)(&print_msg),(void *)msg1);
pthread_create(&thread2,NULL,(void*)(&print_msg),(void* )msg2);
pthread_join(thread1,&retval);
printf("#####################################\n");
printf("*************************************\n");
pthread_join(thread2,&retval);
printf("+++++++++++++++++++++++++++++++++++++\n");
printf("ALL DONE !! MAIN");
return 0;
}
运行结果:
robot@ubuntu:~/Documents/posix/1$ ./demo1join
****Let's go***
_ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ WORLD __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello __ Hello _#####################################
*************************************
+++++++++++++++++++++++++++++++++++++
- 优先级使用数据结构
//参考自a_ran的csdn
struct sched_param
{
int __sched_priority; //所要设定的线程优先级 1 -99 , 数字越大,优先级越高。
}
Linux内核的三种调度策略:
1,SCHED_OTHER 分时调度策略,(不支持优先级)
2,SCHED_FIFO实时调度策略,先到先服务。一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃
3,SCHED_RR实时调度策略,时间片轮转。当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平
设置和获取优先级的函数
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
param.sched_priority = 51; //设置优先级
系统默认创建线程使用的是SCHED_OTHER。 没有优先级。若要更改线程的调度策略,通过如下函数。
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
测试程序:
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
#include <assert.h>
static int get_thread_policy(pthread_attr_t *attr)
{
int policy;
int rs = pthread_attr_getschedpolicy(attr,&policy);
assert(rs==0);
switch(policy)
{
case SCHED_FIFO:
printf("policy= SCHED_FIFO\n");
break;
case SCHED_RR:
printf("policy= SCHED_RR");
break;
case SCHED_OTHER:
printf("policy=SCHED_OTHER\n");
break;
default:
printf("policy=UNKNOWN\n");
break;
}
return policy;
}
static void show_thread_priority(pthread_attr_t *attr,int policy)
{
int priority = sched_get_priority_max(policy);
assert(priority!=-1);
printf("max_priority=%d\n",priority);
priority= sched_get_priority_min(policy);
assert(priority!=-1);
printf("min_priority=%d\n",priority);
}
static int get_thread_priority(pthread_attr_t *attr)
{
struct sched_param param;
int rs = pthread_attr_getschedparam(attr,¶m);
assert(rs==0);
printf("priority=%d",param.__sched_priority);
return param.__sched_priority;
}
static void set_thread_policy(pthread_attr_t *attr,int policy)
{
int rs = pthread_attr_setschedpolicy(attr,policy);
assert(rs==0);
get_thread_policy(attr);
}
int main(void)
{
pthread_attr_t attr;
struct sched_param sched;
int rs;
rs = pthread_attr_init(&attr);
assert(rs==0);
int policy = get_thread_policy(&attr);
printf("Show current configuration of priority\n");
show_thread_priority(&attr,policy);
printf("show SCHED_FIFO of priority\n");
show_thread_priority(&attr,SCHED_FIFO);
printf("show SCHED_RR of priority\n");
show_thread_priority(&attr,SCHED_RR);
printf("show priority of current thread\n");
int priority = get_thread_priority(&attr);
printf("Set thread policy\n");
printf("set SCHED_FIFO policy\n");
set_thread_policy(&attr,SCHED_FIFO);
printf("set SCHED_RR policy\n");
set_thread_policy(&attr,SCHED_RR);
printf("Restore current policy\n");
set_thread_policy(&attr,policy);
rs = pthread_attr_destroy(&attr);
assert(rs==0);
return 0;
}
运行结果:
policy=SCHED_OTHER
Show current configuration of priority
max_priority=0
min_priority=0
show SCHED_FIFO of priority
max_priority=99
min_priority=1
show SCHED_RR of priority
max_priority=99
min_priority=1
show priority of current thread
priority=0Set thread policy
set SCHED_FIFO policy
policy= SCHED_FIFO
set SCHED_RR policy
policy= SCHED_RRRestore current policy
policy=SCHED_OTHER
不同线程调度方案和优先级。
测试程序:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void Thread1()
{
sleep(1);
int i,j;
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR);
printf("SCHED_RR 1 \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for(i=1;i<10;i++)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 1\n");
}
printf("Pthread 1 exit\n");
}
void Thread2()
{
sleep(1);
int i,j,m;
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR);
printf("SCHED_RR\n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for(i=1;i<10;i++)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 2\n");
}
printf("Pthread 2 exit\n");
}
void Thread3()
{
sleep(1);
int i,j;
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR)
printf("SCHED_RR \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for(i=1;i<10;i++)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 3\n");
}
printf("Pthread 3 exit\n");
}
int main()
{
int i;
i = getuid();
if(i==0)
printf("The current user is root\n");
else
printf("The current user is not root\n");
pthread_t ppid1,ppid2,ppid3;
struct sched_param param;
pthread_attr_t attr,attr1,attr2;
pthread_attr_init(&attr1);
pthread_attr_init(&attr);
pthread_attr_init(&attr2);
param.sched_priority = 51;
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);//要使优先级其作用必须要有这句话
param.sched_priority = 21;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
pthread_create(&ppid3,&attr,(void *)Thread3,NULL);
pthread_create(&ppid2,&attr1,(void *)Thread2,NULL);
pthread_create(&ppid1,&attr2,(void *)Thread1,NULL);
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr2);
pthread_attr_destroy(&attr1);
return 0;
}
运行结果:
robot@ubuntu:~/Documents/posix/2$ ./thread2
The current user is not root
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
Pthread 3 exit
robot@ubuntu:~/Documents/posix/2$ sudo ./thread2
[sudo] password for robot:
The current user is root
SCHED_RR 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
Pthread 1 exit
SCHED_RR
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
Pthread 2 exit
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
Pthread 3 exit
robot@ubuntu:~/Documents/posix/2$
- 互斥锁和条件变量
mutual exclusion 互相排斥,互斥锁锁的是线程,而保护公共区域数据,是因为多个线程均使用了互斥锁。
#include <stdio.h>
#include <pthread.h>
#define FALSE 0
#define TRUE 1
void readfun();
void writefun();
char buffer[256]; // 公共数据区
int buf_has_item = 0;//设置数据区的标志位
int retFLAG = FALSE ;//
pthread_mutex_t mutex;//互斥锁全局变量
int main()
{
pthread_t reader;
pthread_mutex_init(&mutex,NULL);
pthread_create(&reader,NULL,(void *)(&readfun),NULL);
writefun();// 先写再读,该处write 速度比新线程要快,所以先看writefun()
return 0;
}
void readfun()
{
while(TRUE)
{
if(retFLAG)
return;
pthread_mutex_lock(&mutex);
if(buf_has_item== 1)
{
printf("%s",buffer);
buf_has_item = 0;
}
pthread_mutex_unlock(&mutex);
}
}
void writefun()
{
int i = 0;//这个i 是和while 要进行遍历,但是下面的if--return ,限制了循环次数。while(1)---return;
//return 的作用是退出循环体所在的函数,相当于结束该方法。
while(TRUE)
{
if(i == 10)
{
retFLAG = TRUE;
return;//return 和循环没关系,就是跳出该函数
}
pthread_mutex_lock(&mutex); //先上锁,新线程阻塞!
if(buf_has_item == 0)//判断状态位置
{
sprintf(buffer,"This is %d\n",i++);
buf_has_item = 1; //该状态位为 readfun()判断使用。
}
pthread_mutex_unlock(&mutex);
}
}
结果为:
robot@ubuntu:~/Documents/posix/3$ ./mutex
This is 0
This is 1
This is 2
This is 3
This is 4
This is 5
This is 6
This is 7
This is 8 //共循环9次。i++ 0-8;如果writefun()中sprintf改成(++i)就会是循环1-9次
- 条件变量
互斥锁只有两个状态,不能满足常用的使用方式,所以条件变量和互斥锁常常搭配使用,控制线程间的工作方式
//初始化条件变量
pthread_cond_t cond;
int pthread_cond_init(pthread_cond_t *cond,const pthread_cond_attr *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond,pthread_murex_t *mutex);
//函数将阻塞,直到条件变量获得信号或者经过abstime指定的时间。
int pthread_cond_timewait(pthread_cond_t *cond,pthread_murex_t *mutex,const struct timespec* abstime);
//发送信号
int pthread_cond_signal(pthread_cond_t *cond)
//使得所有关于由参数cond 指向的条件变量阻塞的线程退出阻塞状态。参数没有mutex,并不指向使用锁的且阻塞的线程。
int pthread_cond_broadcast(pthread_cond_t *cond)
条件变量demo
#include <pthread.h>
#include <iostream>
using namespace std;
#define BOUNDARY 5 //全局变量
int task = 10;
pthread_mutex_t task_mutex;//锁
pthread_cond_t task_cond;//条件变量,设为全局
void* say_hello2(void* args)
{
pthread_t pid = pthread_self();//获得线程资源编号
cout<< "["<< pid << "] hello in thread" << *((int*)args)<< endl;
bool is_signaled = false ; //随便设置的标志位,用于条件切换,发送信号
while(1)
{
pthread_mutex_lock(&task_mutex);//先锁,再判断。
if(task > BOUNDARY)
{
cout << "["<<pid <<"] take task :"<< task << "in thread"<<*((int*)args) << endl;
--task;
}
else if (!is_signaled)
{
cout << "["<<"] pthread_cond_signal in thread " << *((int *)args)<< endl;
pthread_cond_signal(&task_cond);//重点发送信号
is_signaled = true ;
}
pthread_mutex_unlock(&task_mutex);
if(task == 0)// 用于跳出while
break;
}
}
void* say_hello1(void* args)
{
pthread_t pid = pthread_self();
cout << "["<<pid <<"] hello in thread "<< *((int*)args) << endl;
while(1)
{
pthread_mutex_lock(&task_mutex);
if(task > BOUNDARY)
{
cout <<"["<< pid <<"] pthread_cond_wait in thread" << *((int*) args) << endl;
pthread_cond_wait(&task_cond,&task_mutex);//重点,收到信号前阻塞
}
else
{
cout << "["<< pid << "] take task:"<< task << "in thread "<< *((int* )args) << endl;
--task;
}
pthread_mutex_unlock(&task_mutex);
if(task ==0)//小于5时,会空循环5次,直到==0,break
break;
}
}
int main()
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);//为下面Join
pthread_mutex_init(&task_mutex,NULL);
pthread_cond_init(&task_cond,NULL);
pthread_t tid1,tid2;
int index1 =1, index2 =2 ;
int ret1 = pthread_create(&tid1,&attr,say_hello1,(void*)&index1);
if(ret1 != 0)
cout << "pthread 1 create failed ! error code is "<< ret1 << endl;
int ret2 = pthread_create(&tid2,&attr,say_hello2,(void*)&index2);
if(ret2 !=0)
cout << "pthread 2 create failed ! error code is "<< ret2 << endl;
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&task_mutex);
pthread_cond_destroy(&task_cond);
return 0;
}
运行结果:
robot@ubuntu:~/Documents/posix/3$ ./cond1
[140355188872960] hello in thread2
[140355188872960] take task :10in thread2
[140355188872960] take task :9in thread2
[140355188872960] take task :8in thread2
[140355188872960] take task :7in thread2
[140355188872960] take task :6in thread2
[] pthread_cond_signal in thread 2
[140355197265664] hello in thread 15
[140355197265664] take task:5in thread 1
[140355197265664] take task:4in thread 1
[140355197265664] take task:3in thread 1
[140355197265664] take task:2in thread 1
[140355197265664] take task:1in thread 1