线程的创建:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数介绍:
pthread_t *thread ------------------------用于标识一个线程
const pthread_attr_t *attr--------------该指针用来指定线程的属性,若为NULL则线程为默认属性。
void *(*start_routine) (void )---------指向一个返回值是void的函数指针,函数入口参数为void *型;该函数是线程运行函数;
void *arg-------------------线程函数运行时需要传入的参数。
线程的退出
void pthread_exit(void *retval);
参数介绍:
void *retval:线程调用函数退出时,向进程传递的信息,可以是结构体。
进程中的其他线程(包括进程本身)可以调用pthread_join()来访问这个指针。
线程的等待
int pthread_join(pthread_t thread, void **retval);
返回值:成功返回0,失败返回错误编号。
thread:为创建线程时指定的线程ID号。
void **retval:一个二级指针,来接收线程返回时传递的信息。
下面代码是简单的创建一个线程
#include
#include
#include
#include
void *fun1(void *par)
{
while(1)
{
printf("t1: ID = %ld \n",pthread_self()); //pthread_self();获取当前线程的ID号
sleep(1);
}
pthread_exit(NULL); //线程退出可以返回值,这里写NULL,不返回
}
int main(int argc, char **argv)
{
int ret;
pthread_t t1; //创建线程标识符
ret = pthread_create(&t1,NULL,fun1,NULL); //创建线程,返回值为0代表创建成功
if(ret == 0)
{
printf("pthread t1 success \n");
}
pthread_join(t1,NULL); //等待某个线程退出,第二个参数可以获取返回值,暂且不获取。写NULL,如果不等待线程退出,当main函数结束时,线程随之结束。
return 0;
}
程序执行结果:
在执行线程的时候要在main函数里面等待线程退出,否则当main函数控制线程退出后,线程也会随之退出。
pthread_join(t1,NULL);
该函数等待线程t1退出,并且不获取线程t1的参数。
互斥所的作用:
我们开启多个线程时,线程的资源是共享的,多个线程同时跑起来时,会交叉的运行,具体谁先运行,谁后运行看linux内核的调度。
当我们想要一个线程执行完后再去执行另外一个线程时,我们就需要对线程进行“加锁”和“解锁”。对线程加锁之后,其他想要访问这个线程里面的资源时,需要等到加锁线程解锁后才能访问。
下面是一个线程的加锁和解锁:
void *fun1(void *par)
{
pthread_mutex_lock(&mutex);
printf("t1 : this is pthread one par=%d\n",*((int*)par));
printf("t1 : this is t1 g_data = %d\n",g_data++);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
加锁之后线程会执行完两个printf函数进行解锁,加锁之后,会保证锁里面的内容执行完后再执行其他的,但是“加锁”和“解锁”的操作不能保证哪个线程先运行。
互斥锁的初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
我们在使用互斥锁时要先对互斥锁进行初始化。
参数介绍:
pthread_mutex_t *restrict mutex
互斥锁变量用 pthread_mutex_t 类型进行定义。
const pthread_mutexattr_t *restrict attr
锁的属性设置,一般写NULL要具体用的时候可以看一下参数介绍。
互斥锁的销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数介绍:
pthread_mutex_t *mutex
销毁哪一把锁。
加锁和解锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
我们看没有加锁的情况
#include
#include
#include
#include
int g_data = 0;
//pthread_mutex_t mutex;
void *fun1(void *par)
{
int i = 0;
// pthread_mutex_lock(&mutex);
while(1)
{
i++;
if(i==3)
{
break;
}
printf("t1 : this is pthread one par=%d\n",*((int*)par));
sleep(1);
printf("t1 : this is t1 g_data = %d\n",g_data++);
}
// pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void *fun2(void *par)
{
int i = 0;
// pthread_mutex_lock(&mutex);
while(1)
{
i++;
if(i==3)
{
break;
}
printf("t2 : this is pthread two par=%d\n",*((int*)par));
sleep(1);
printf("t2 : this is t1 g_data = %d \n",g_data++);
}
// pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int ret;
pthread_t t1;
pthread_t t2;
int param = 100;
// pthread_mutex_init(&mutex,NULL);
ret = pthread_create(&t1,NULL,fun1,(void*)¶m); //创建线程
if(ret == 0)
{
printf("pthread t1 success \n");
}
ret = pthread_create(&t2,NULL,fun2,(void*)¶m); //创建线程
if(ret == 0)
{
printf("pthread t2 success \n");
}
printf("this is main thread id =%ld \n",(unsigned long)pthread_self());
pthread_join(t1,NULL);
pthread_join(t2,NULL);
// pthread_mutex_destroy(&mutex);
return 0;
}
执行结果:
我们可以看到,没有上锁时,t1和t2线程交叉执行,t1和t2线程在竞争资源。
我们看上了锁之后:
#include
#include
#include
#include
int g_data = 0;
pthread_mutex_t mutex;
void *fun1(void *par)
{
int i = 0;
pthread_mutex_lock(&mutex);
while(1)
{
i++;
if(i==3)
{
break;
}
printf("t1 : this is pthread one par=%d\n",*((int*)par));
sleep(1);
printf("t1 : this is t1 g_data = %d\n",g_data++);
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void *fun2(void *par)
{
int i = 0;
pthread_mutex_lock(&mutex);
while(1)
{
i++;
if(i==3)
{
break;
}
printf("t2 : this is pthread two par=%d\n",*((int*)par));
sleep(1);
printf("t2 : this is t1 g_data = %d \n",g_data++);
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int ret;
pthread_t t1;
pthread_t t2;
int param = 100;
pthread_mutex_init(&mutex,NULL);
ret = pthread_create(&t1,NULL,fun1,(void*)¶m); //创建线程
if(ret == 0)
{
printf("pthread t1 success \n");
}
ret = pthread_create(&t2,NULL,fun2,(void*)¶m); //创建线程
if(ret == 0)
{
printf("pthread t2 success \n");
}
printf("this is main thread id =%ld \n",(unsigned long)pthread_self());
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
执行结果:
当一个线程里面解锁之后别的线程回去竞争这个锁,竞争到锁的线程进行上锁,等到解锁之后别的线程才能竞争。
条件变量的作用
条件变量用来跟互斥量一起使用,在一个线程里面可以触发一个信号,另外一个线程等待触发线程的信号后执行当前线程。
//条件变量的创建
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);
//多了一个等待时间参数*restrict timeout
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);
//信号触发
int pthread_cond_signal(pthread_cond_t cond);
//信号广播
int pthread_cond_broadcast(pthread_cond_t cond);
线程条件变量的创建
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
参数介绍:
pthread_cond_t *restrict cond
条件变量pthread_cond_t 定义
const pthread_condattr_t *restrict attr
除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。
线程条件变量的销毁
int pthread_cond_destroy(pthread_cond_t cond);
参数介绍:
pthread_cond_t cond
需要销毁的条件变量
信号的触发
//信号触发
int pthread_cond_signal(pthread_cond_t cond);
经常与int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
函数一起使用。
当一个线程信号触发时,另一个线程等到这个触发信号时当前线程开始执行。
我们来看函数的简单使用:
#include
#include
#include
#include
int g_data = 0;
pthread_mutex_t mutex; //定义一个锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //静态初始化条件变量cond
void *fun1(void *par)
{
static int cont = 0;
// static int ret = 10;
static char* str = "hello word";
while(1)
{
pthread_cond_wait(&cond,&mutex);
printf("t1 : this is t1 g_data = %d\n",g_data);
g_data = 0;
cont++;
if(cont == 5)
{
exit(0);
}
}
pthread_exit((void*)str); //线程退出返回值
}
void *fun2(void *par)
{
// static int ret = 10;
printf("%d \n",*((int *)par));
static char* str = "nice baby";
while(1)
{
printf("t2 : this is t1 g_data = %d \n",g_data++);
if(g_data == 3)
{
pthread_cond_signal(&cond); //发送信号
}
sleep(1);
}
pthread_exit((void*)str);
}
int main(int argc, char **argv)
{
int ret;
pthread_t t1;
pthread_t t2;
int param = 100;
char *prr = NULL;
pthread_mutex_init(&mutex,NULL);
ret = pthread_create(&t1,NULL,fun1,(void*)¶m); //创建线程
if(ret == 0)
{
printf("pthread t1 success \n");
}
ret = pthread_create(&t2,NULL,fun2,(void*)¶m); //创建线程
if(ret == 0)
{
printf("pthread t2 success \n");
}
printf("this is main thread id =%ld \n",(unsigned long)pthread_self());
pthread_join(t1,(void**)&prr);
pthread_join(t2,(void**)&prr);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
线程2的变量g_data加到3时,触发信号,线程1等到信号触发是时执行程序。
执行结果如下:
pthread t1 success
pthread t2 success
this is main thread id =140428182296384
100
t2 : this is t1 g_data = 0
t2 : this is t1 g_data = 1
t2 : this is t1 g_data = 2
t1 : this is t1 g_data = 3
t2 : this is t1 g_data = 0
t2 : this is t1 g_data = 1
t2 : this is t1 g_data = 2
t1 : this is t1 g_data = 3