Linux线程介绍
进程与线程
进程是程序执行时的一个实例,是担当分配系统资源(CPU时间、内存等)的基本单位。在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器。
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
从函数调用上来说,进程创建使用fork()操作;线程创建使用clone()操作。
使用线程的理由
进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。
使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。
使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。
数据共享带来其他的一些问题我们可以用条件变量和互斥锁来解决。
demo1,demo2,demo3讲述线程创建,退出,等待的API
demo4 线程共享内存空间
demo5 互斥锁创建及销毁,加锁及解锁
demo6 利用互斥锁让t1在等于3的时候退出(绝对退出)
demo7 死锁怎么造成的
demo8 关于创建销毁等待触发条件的API
demo9 关于动态静态初始化,生产者消费者的使用
.sh是脚本文件,chmod +x xxx.sh可以给他执行权限
pthread_create函数(线程创建)
若成功返回0,否则返回错误编号
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
thread:新创建线程的线程ID
attr:用于定制各种不同的线程属性,暂可以把它设置为NULL,以创建默认属性的线程。
start_routine:函数指针
arg:第三个参数函数传递的参数,如果需要向函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
pthread_join函数(线程等待)
成功返回0,否则返回错误编号
调用这个函数的线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
thread:线程ID
retval:线程返回值,对线程返回值不感兴趣,可以设置为NULL
pthread_exit函数(线程退出)
#include <pthread.h>
void pthread_exit(void *retval);
retva:无类型指针,与传给启动历程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问这个指针
pthread_self与pthread_equal函数(线程ID获取及比较)
对于线程ID比较,为了可移植操作,我们不能简单地把线程ID当作整数来处理,因为不同系统对线程ID的定义可能不一样。我们应该要用下边的pthread_equal函数
#include <pthread.h>
pthread_t pthread_self(void);
返回:调用线程的ID
int pthread_equal(pthread_t tid1, pthread_t tid2);
返回:若相等返回非0值,否则返回0
pthread_mutex_init与pthread_mutex_destroy函数(创建及销毁互斥锁)
成功返回0,否则返回错误编号
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
mutex:一个指针,用pthread_mutex_t数据类型表示
attr:互斥量,只需把attr设置为NULL,用默认的属性初始化
int pthread_mutex_destroy(pthread_mutex_t *mutex);
mutex:销毁你创建的参数指针
pthread_mutex_lock与pthread_mutex_unlock函数(加锁及解锁)
成功返回0,否则返回错误编号
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
mutex:创建的参数指针
int pthread_mutex_unlock(pthread_mutex_t *mutex);
mutex:创建的参数指针
pthread_cond_init与pthread_cond_destroy函数(创建及销毁条件变量)
成功返回0,否则返回错误编号
条件变量使用之前必须首先初始化,pthread_cond_t数据类型代表的条件变量可以用两种方式进行初始化,可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,但是如果条件变量是动态分配的,可以使用pthread_cond_destroy函数对条件变量进行去除初始化。
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
cond:一个指针,用pthread_cond_t数据类型表示
attr:除非需要创建一个非默认属性的条件变量,否则attr参数可以设置为NULL。
int pthread_cond_destroy(pthread_cond_t *cond);
cond:销毁你创建的参数指针
pthread_cond_wait和pthread_cond_timedwait函数(等待)
成功返回0,否则返回错误编号
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
cond:创建的条件参数
mutex:创建的线程参数
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);
cond:创建的条件参数
mutex:创建的线程参数
timeout:指定等待的时间
pthread_cond_signal和pthread_cond_broadcast函数(触发)
成功返回0,否则返回错误编号
这两个函数可以用于通知线程条件已经满足。pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast函数将唤醒等待该条件的所有进程。
注意一定要在改变条件状态以后再给线程发信号。
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
cond:创建的条件参数
int pthread_cond_broadcast(pthread_cond_t *cond);
cond:创建的条件参数
结合所讲的函数代码
/****************************demo1****************************/
#include <stdio.h>
#include <pthread.h>
// int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
void *fun1(void *arg)
{
printf("t1:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t1:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
}
int main()
{
pthread_t t1;
int num = 10;
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,
//暂可以把它设置为NULL,以创建默认属性的线程。第三个参数是一个函数指针,第四个参数是第三个参数函数传递的参数,如果需要向函数传递的
//参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
while(1); //无限循环
return 0;
}
/****************************demo2****************************/
#include <stdio.h>
#include <pthread.h>
// int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
// int pthread_join(pthread_t thread, void **retval);
// void pthread_exit(void *retval);
void *fun1(void *arg)
{
static int ret = 10;
printf("t1:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t1:arg = %d\n",*((int *)arg)); //打印传递过来的值,100
pthread_exit((void *)&ret); //调用退出,返回值是10
}
int main()
{
int *p = NULL;
pthread_t t1;
int num = 100;
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,
//暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,如果需要向函数传递的
//参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
if(ret == 0){
printf("main:create t1 success\n");
}
printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
pthread_join(t1,(void **)&p); //调用这个函数的线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
//第二个参数是exit返回的参数
printf("main:t1 quit:%d\n",*p); //打印这个返回的内容,10
// while(1);
return 0;
}
/****************************demo3****************************/
#include <stdio.h>
#include <pthread.h>
// int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
// int pthread_join(pthread_t thread, void **retval);
// void pthread_exit(void *retval);
void *fun1(void *arg)
{
static char *ret = "t1 is run out";
printf("t1:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t1:arg = %d\n",*((int *)arg)); //打印传递过来的值,100
pthread_exit((void *)ret); //调用退出,返回值是t1 is run out
}
int main()
{
char *p = NULL;
pthread_t t1;
int num = 100;
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,
//暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,如果需要向函数传递的
//参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
if(ret == 0){
printf("main:create t1 success\n");
}
printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
pthread_join(t1,(void **)&p); //调用这个函数的线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
//第二个参数是exit返回的参数
printf("main:t1 quit:%s\n",p); //打印这个返回的内容,t1 is run out
// while(1);
return 0;
}
/****************************demo4****************************/
#include <stdio.h>
#include <pthread.h>
// int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
int g_data = 0;
void *fun1(void *arg)
{
printf("t1:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t1:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
while(1){
sleep(1);
printf("t1: %d\n",g_data++);
if(g_data == 3){
pthread_exit(NULL);
}
}
}
void *fun2(void *arg)
{
printf("t2:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t2:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
while(1){
sleep(1);
printf("t2: %d\n",g_data++);
}
}
int main()
{
pthread_t t1;
pthread_t t2;
int num = 10;
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,
//暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,如果需要向函数传递的
//参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传>入。
ret = pthread_create(&t2,NULL,fun2,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,
//暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,如果需要向函数
//传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
while(1){
sleep(1);
printf("main: %d\n",g_data++);
}
pthread_join(t1,NULL);
pthread_join(t2,NULL);
while(1); //无限循环
return 0;
}
/****************************demo5****************************/
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
//1. 创建及销毁互斥锁
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//int pthread_mutex_destroy(pthread_mutex_t mutex);
//2. 加锁及解锁
//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 g_data = 0;
pthread_mutex_t mutex;
void *fun1(void *arg)
{
pthread_mutex_lock(&mutex); //加锁,设一个全局变量取地址
printf("t1:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t1:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
pthread_mutex_unlock(&mutex); //解锁,你加锁的地址
}
void *fun2(void *arg)
{
pthread_mutex_lock(&mutex); //加锁,设一个全局变量取地址
printf("t2:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t2:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
pthread_mutex_unlock(&mutex); //解锁,你加锁的地址
}
void *fun3(void *arg)
{
pthread_mutex_lock(&mutex); //加锁,设一个全局变量取地址
printf("t3:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t3:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
pthread_mutex_unlock(&mutex); //解锁,你加锁的地址
}
int main()
{
pthread_t t1;
pthread_t t2;
pthread_t t3;
int num = 10;
pthread_mutex_init(&mutex,NULL); //创建锁,第一个参数是一个指针,在上面定义了一个全局变量,第二个参数要用默认的属性初始化
//互斥量,只需把attr设置为NULL。
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程
//属性,暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,如果需
//要向函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
ret = pthread_create(&t2,NULL,fun2,(void *)&num);
ret = pthread_create(&t3,NULL,fun3,(void *)&num);
printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
pthread_join(t1,NULL); //调用这个函数的线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
//第二个参数是exit返回的参数
pthread_join(t2,NULL);
pthread_join(t3,NULL);
pthread_mutex_destroy(&mutex); //销毁锁,销毁你创建的参数指针
//while(1); //无限循环
return 0;
}
/****************************demo6****************************/
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
int g_data = 0;
pthread_mutex_t mutex;
void *fun1(void *arg)
{
printf("t1:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t1:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
pthread_mutex_lock(&mutex); //加锁
while(1){
sleep(1);
printf("t1: %d\n",g_data++);
if(g_data == 3){
pthread_mutex_unlock(&mutex); //解锁
printf("t1 quit===========================\n");
pthread_exit(NULL);
}
}
}
void *fun2(void *arg)
{
printf("t2:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t2:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
while(1){
sleep(1);
printf("t2: %d\n",g_data);
pthread_mutex_lock(&mutex); //如果t2先获得执行权那就g_data++,运行结束后等于g_data=1,然后fun1获得执行权,
//因为fun1的解锁放在了之后在t1等于3的时候才解锁,所以无论t2获得加锁的权利,都不可能打断t1的运行,因为t1还没有
//解锁,所以t2会一直阻塞到t1解锁
g_data++;
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
}
int main()
{
pthread_t t1;
pthread_t t2;
int num = 10;
pthread_mutex_init(&mutex,NULL);
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,
//暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,如果需要向函数传递
//的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
ret = pthread_create(&t2,NULL,fun2,(void *)&num);
printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_mutex_destroy(&mutex);
//while(1); //无限循环
return 0;
}
/****************************demo7****************************/
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
//1. 创建及销毁互斥锁
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//int pthread_mutex_destroy(pthread_mutex_t *mutex);
//2. 加锁及解锁
//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 g_data = 0;
pthread_mutex_t mutex; //造成死锁的前提是最少要两把锁
pthread_mutex_t mutex2;
void *fun1(void *arg)
{
pthread_mutex_lock(&mutex);
sleep(1);
pthread_mutex_lock(&mutex2); //线程1想要去获取线程2的锁,而下面线程2有线程1想要获取的锁,线程2也想获取线程1的锁,
//两个都想获取对方手里的那把锁,都不肯解锁,这样就导致了死锁
printf("t1:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t1:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
pthread_mutex_unlock(&mutex);
}
void *fun2(void *arg)
{
pthread_mutex_lock(&mutex2);
sleep(1);
pthread_mutex_lock(&mutex);
printf("t2:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t2:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
pthread_mutex_unlock(&mutex);
void *fun3(void *arg)
{
pthread_mutex_lock(&mutex);
printf("t3:%ld create pthread success\n",(unsigned long)pthread_self()); //获得线程自身的ID。
printf("t3:arg = %d\n",*((int *)arg)); //打印传递过来的值,10
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_t t1;
pthread_t t2;
pthread_t t3;
int num = 10;
pthread_mutex_init(&mutex,NULL);
pthread_mutex_init(&mutex2,NULL);
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的
//线程属性,暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,
//如果需要向函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传>入。
ret = pthread_create(&t2,NULL,fun2,(void *)&num);
ret = pthread_create(&t3,NULL,fun3,(void *)&num);
printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
pthread_join(t1,NULL); //调用这个函数的线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返>回或者被取消。
//第二个参数是exit返回的参数
pthread_join(t2,NULL);
pthread_join(t3,NULL);
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex2);
//while(1); //无限循环
return 0;
}
/****************************demo8****************************/
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
int g_data = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *fun1(void *arg)
{
while(1){
pthread_cond_wait(&cond,&mutex);
printf("t1 run===========================\n");
printf("t1: %d\n",g_data);
g_data=0;
sleep(1);
}
}
void *fun2(void *arg)
{
while(1){
sleep(1);
printf("t2: %d\n",g_data);
pthread_mutex_lock(&mutex);
g_data++;
if(g_data == 3){
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t t1;
pthread_t t2;
int num = 10;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,
//暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,如果需要向函数传递
//的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传>入。
ret = pthread_create(&t2,NULL,fun2,(void *)&num);
// printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
/****************************demo9****************************/
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
int g_data = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //静态初始化
void *fun1(void *arg)
{
while(1){
pthread_cond_wait(&cond,&mutex);
printf("t1 run===========================\n");
printf("t1: %d\n",g_data);
g_data=0;
sleep(1);
}
}
void *fun2(void *arg)
{
while(1){
sleep(1);
printf("t2: %d\n",g_data);
pthread_mutex_lock(&mutex);
g_data++;
if(g_data == 3){
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t t1;
pthread_t t2;
int num = 10;
// pthread_mutex_init(&mutex,NULL); //动态初始化
// pthread_cond_init(&cond,NULL); //动态初始化
int ret = pthread_create(&t1,NULL,fun1,(void *)&num); //t1被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,
//暂可以把它设置为NULL,以创建默认属性的线程。第三个参数时一个函数指针,第四个参数是第三个参数函数传递的参数,如果需要向函数传递
//的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
ret = pthread_create(&t2,NULL,fun2,(void *)&num);
// printf("main:%ld\n",(unsigned long)pthread_self()); //获得线程自身的ID。
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}