目录
一、线程
1、程序与线程
- 进程:是指⼀个内存中运⾏的应⽤程序,每个进程都有⼀个独⽴的内存空间,⼀个应⽤程序可以同时运⾏多个进程;进程也是程序的⼀次执⾏过程,是系统运⾏程序的基本单位;系统运⾏⼀个程序即是 ⼀个进程从创建、运⾏到消亡的过程。
- 线程:线程是进程中的⼀个执⾏单元,负责当前进程中程序的执⾏,⼀个进程中⾄少有⼀个线程。⼀个进程中是可以有多个线程的,这个应⽤程序也可以称之为多线程程序。
2、 Linux线程开发API
对象 | 操作 | API |
线程 | 创建 | pthread_create |
退出 | pthread_exit | |
等待 | pthread_join | |
互斥锁 | 创建 | pthread_mutex_init |
销毁 | pthread_mutex_destroy | |
加锁 | pthread_mutex_lock | |
解锁 | pthread_mutex_unlock | |
条件 | 创建 | pthread_cond_init |
销毁 | pthread_cond_destroy | |
触发 | pthread_cond_signal | |
广播 | pthread_cond_broadcast | |
等待 | pthread_cond_wait/pthead_cond_timedwat |
2.1、线程创建
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
参数说明:
tidp:当线程成功创建后,tidp指向的内存单元被设置为新创建线程的线程ID。
attr:设置为NULL可以创建默认属性的线程。
start_rtn:新创建的线程从此函数开始运行,该函数只有一个无类型指针参数arg。如果需要向该函数传递的参数不止一个,则需要创建一个结构体放这些参数,然后把这个结构体的地址作为arg参数传入。
返回值:若成功返回0,否则返回错误编号
2.2、线程退出
#include <pthread.h>
int pthread_exit(void *rval_ptr);
参数说明:
rval_ptr:无类型的指针
2.3、线程等待
调用这个函数的线程一直被阻塞
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
2.4、线程ID获取
#include <pthread.h>
pthread_t pthread_self(void);
返回值:线程ID
例1:创建t1线程
#include <stdio.h>
#include <pthread.h>
//创建线程时,参数:函数(该线程需要做什么)
void *func1(void *arg)
{
static char *p = "t1 is run out\n";
//static:必须加上,否则线程结束,此数据也不存在
//char型指针p是线程退出API的参数
printf("t1:%ld thread is created\n",(unsigned long)pthread_self());
//获取t1线程的ID,并转换成长整型
printf("t1:param is %d\n",*((int *)arg));
//将创建线程时函数参数打印出来(第4个参数)
//*((int *)arg):arg为void型指针,强转为int型即:(int *)arg;
//然后再取该地址中的数据,即*((int *)arg)
pthread_exit((void *)p);
//t1线程退出,会有一个指针参数(主线程join时要获取此参数)
//将char型指针强转为void型指针
}
int main()
{
int ret;//创建线程的返回值
int param = 100;//第4个参数,函数的参数
pthread_t t1;//线程名
char *pret = NULL;//创建一个char型指针,为join接收t1线程的exit的参数
ret = pthread_create(&t1,NULL,func1,(void *)¶m);//创建线程
//返回值为0,创建成功
if(ret == 0){
printf("main:create ti is success\n");
}
printf("main:%ld\n",(unsigned long)pthread_self());//打印主线程的ID
pthread_join(t1,(void **)&pret);
//等待t1退出,t1退出会给主线程传回一个参数,即第二个参数
//第一个参数是线程名
//第二个参数是一个void型的二级指针,pret本身就是一个char型指针,取它地址然后再强转void
printf("main:t1 is quit:%s\n",pret);//将t1退出传回来的数据打印出来
return 0;
}
运行结果:
main:create ti is success
main:140139917944576
t1:140139909658368 thread is created
t1:param is 100
main:t1 is quit:t1 is run out
2.5、创建与销毁互斥锁
锁的作用:上了锁的线程,一旦开始执行,不会被其他线程打断,直到该线程运行完成结束。
#include <pthread.h>
①创建
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
参数说明:
mutex:锁名
attr:NULL
②销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
2.6、加锁与解锁
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
例2:加锁
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t m1;//锁名
void *func1(void *arg)
{
int i;
pthread_mutex_lock(&m1);//给线程1的执行函数加锁
for(i=0;i<5;i++)
{
printf("t1:%ld thread is created\n",(unsigned long)pthread_self());
printf("t1:param is %d\n",*((int *)arg));
sleep(2);
}
pthread_mutex_unlock(&m1);//解锁
}
void *func2(void *arg)
{
pthread_mutex_lock(&m1);//给线程2的执行函数加锁
printf("t2:%ld thread is created\n",(unsigned long)pthread_self());
printf("t2:param is %d\n",*((int *)arg));
pthread_mutex_unlock(&m1);//解锁
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
pthread_t t2;
ret = pthread_create(&t1,NULL,func1,(void *)¶m);
if(ret == 0){
printf("main:create t1 is success\n");
}
ret = pthread_create(&t2,NULL,func2,(void *)¶m);
if(ret == 0){
printf("main:create t2 is success\n");
}
return 0;
}
运行结果:(t1先打印5次,每2秒一次,之后t2再执行,但是main没有锁会穿插其中)
main:create t1 is success
t1:139785596000000 thread is created
t1:param is 100
main:create t2 is success
t1:139785596000000 thread is created
t1:param is 100
t1:139785596000000 thread is created
t1:param is 100
t1:139785596000000 thread is created
t1:param is 100
t1:139785596000000 thread is created
t1:param is 100
t2:139785587607296 thread is created
t2:param is 100
2.7、条件的创建与销毁
条件的作用:当一个线程被锁住时,达到一定条件时,想让另一个线程去运行。
#include <pthread.h>
①创建
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
②销毁
int pthread_cond_destroy(pthread_cond_t cond);
返回值:若成功返回0,失败返回错误编号
2.8、等待
条件被创建后,某一线程需要去等待这个条件成立,然后该线程去运行
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);
2.9、触发
int pthread_cond_signal(pthread_cond_t cond);//单次触发
int pthread_cond_broadcast(pthread_cond_t cond); //广播
例3、线程t1当g_data=3时运行,线程t2上锁
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t m;//锁名
pthread_cond_t c;//条件名
int g_data = 0;//临界资源
void *func1(void *arg)
{
printf("t1:%ld thread is created\n",(unsigned long)pthread_self());
printf("t1:param is %d\n",*((int *)arg));
while(1){
pthread_cond_wait(&c,&m);//t1线程等待条件成立
printf("t1 run--------------\n");
printf("t1:%d\n",g_data);
g_data = 0;
sleep(1);
}
}
void *func2(void *arg)
{
printf("t2:%ld thread is created\n",(unsigned long)pthread_self());
printf("t2:param is %d\n",*((int *)arg));
while(1){
printf("t2:%d\n",g_data);
pthread_mutex_lock(&m);//t2上锁
g_data++;
if(g_data == 3){
pthread_cond_signal(&c);//触发条件
}
pthread_mutex_unlock(&m);//t2解锁
sleep(1);
}
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
pthread_t t2;
pthread_mutex_init(&m,NULL);//锁初始化
pthread_cond_init(&c,NULL);//条件初始化
ret = pthread_create(&t1,NULL,func1,(void *)¶m);
if(ret == 0){
// printf("main:create t1 is success\n");
}
ret = pthread_create(&t2,NULL,func2,(void *)¶m);
if(ret == 0){
// printf("main:create t2 is success\n");
}
pthread_mutex_destroy(&m);//销毁锁
pthread_cond_destroy(&c);//销毁条件
return 0;
}
运行结果:
t1:140324597438208 thread is created
t1:param is 100
t2:140324589045504 thread is created
t2:param is 100
t2:0
t2:1
t2:2
t1 run--------------
t1:3
t2:0
t2:1
t2:2
t1 run--------------
t1:3
t2:0
t2:1
t2:2
t1 run--------------
t1:3
t2:0
t2:1
t2:2
t1 run--------------
t1:3
t2:0
t2:1
t2:2
...