线程:线程是进程的一个实体,是被系统独立调度和分派的基本单位,是一个进程并发执行多个任务的机制。
并发:单核CPU多任务同时运行,CPU以ms级进行进程调度
进程间的切换表现为上下文的切换:
上下文:运行一个进程所需要的所有资源
上下文切换:从访问进程1到访问进程2,CPU访问的资源要替换原有内容,这个操作本身是一个耗时操作
为了减少进程创建、撤销和切换时所付出的时空开销,使操作系统有更好的并发性,把资源的分配单位和调度单位分开,提出了线程。
线程属于进程,每一个进程至少有一个线程作为指令执行体,线程运行在进程空间内,一个进程中可以有多个线程,因此程序也被称为多线程程序。
功能:创建一个线程
函数原型:
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
参数:
pthread_t *thread:存储创建后的线程id号
pthread_attr_t *attr:线程的属性,填NULL。如果要设置,该位置需要通过pthread_attr_init初始化属性,可以设置分离属性 void *(*start_routine) (void *):函数指针,该指针指向线程的任务执行体。该指针可以指向返回值是void*类型,参数列表是void*类型的函数,例如:void* callBack(void* arg){}
void *arg:传递给函数指针指向的函数的参数
返回值:
成功,返回0
失败,返回错误编号,即非0
定义一个全局变量,int a = 10,主线程和分支线程均能访问到,访问到的资源为同一份资源(即临界资源)
在主线程定义一个局部变量,int b = 10,分支线程不能访问,同样,在分支线程定义一个局部变量,int c = 10,主线程不能访问。因为局部变量的生命周期以及作用域有限,那么如何实现这些资源的共享?
1)主线程传参给分支线程
#include
#include
#include
//线程执行体
void* callBack(void* arg) //void* arg = &c
{
while(1)
{
printf("this is other func c=%d %p __%d__\n", *(int *)arg, arg,__LINE__);
sleep(1);
}
return NULL;
}
int main(int argc, const char *argv[])
{
//主线程定义一个局部变量
int c = 10;
//创建线程
pthread_t tid;
if(pthread_create(&tid, NULL, callBack, &c) != 0)
{
fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
return -1;
}
while(1)
{
printf("this is main function c=%d %p __%d__\n", c, &c, __LINE__);
sleep(1);
}
return 0;
}
2)分支线程传承给主线程
#include
#include
#include
//线程执行体
void* callBack(void* arg) //void* arg = &c
{
//分支线程定义一个局部变量
int b = 10;
*(int *)arg = &b;
while(1)
{
printf("this is other func b=%d %p __%d__\n", b, &b,__LINE__);
sleep(1);
}
return NULL;
}
int main(int argc, const char *argv[])
{
int get_b;
//创建线程
pthread_t tid;
if(pthread_create(&tid, NULL, callBack, &get_b) != 0)
{
fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
return -1;
}
while(1)
{
printf("this is main function b=%d %p __%d__\n", get_b, &get_b, __LINE__);
sleep(1);
}
return 0;
}
此时,主线程与分支线程打印的变量,值相等,地址不相等,若想它们的地址也相等我们可以用以下方法:
#include
#include
#include
//线程执行体
void* callBack(void* arg) //void* arg = &c
{
//分支线程定义一个局部变量
int b = 10;
*(int **)arg = &b;
while(1)
{
printf("this is other func b=%d %p __%d__\n", b, &b,__LINE__);
sleep(1);
}
return NULL;
}
int main(int argc, const char *argv[])
{
int *get_b = NULL;
//创建线程
pthread_t tid;
if(pthread_create(&tid, NULL, callBack, &get_b) != 0)
{
fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
return -1;
}
while(1)
{
printf("this is main function b=%d %p __%d__\n", *get_b, get_b, __LINE__);
sleep(1);
}
return 0;
}
功能:退出线程,并传递线程退出状态值,线程退出后,会残留一部分资源,该资源可以被pthread_join回收
函数原型:
#include
void pthread_exit(void *retval);
参数:
void *retval:可以传递线程退出状态值,可以是任意类型数据;。数据会被pthread_join函数接收。参数可以填NULL,代表不返回任何数据
功能:阻塞函数,阻塞等待指定的线程退出。 线程退出后,会残留一部分资源,该资源可以被pthread_join回收
函数原型:
#include
int pthread_join(pthread_t thread, void **retval);
参数:
pthread_t thread:指定要等待、回收哪一个线程的资源; void **retval:如果该参数不为NULL,则线程退出状态值会被拷贝到,当前指针指向的内存空间中。 填NULL,代表不接收退出状态值
返回值:
成功,返回0
失败,返回错误码,即非0
功能:分离线程,线程退出后,由内核自动回收资源。不需要其他线程再调用pthread_join回收。当主线程有自己任务的时候,无法用pthread_join回收线程资源时,选择pthread_detach函数,自动回收资源
函数原型:
#include
int pthread_detach(pthread_t thread);
参数:
pthread_t thread:指定要分离的线程的tid号
返回值:
成功,返回0
失败,返回错误码,即非0
注意:当使用pthread_detach分离指定线程后,pthread_join函数将无法回收该线程资源,且pthread_join函数不再阻塞
功能:用一个线程请求另外一个指定线程退出,请求成功,不代表目标线程一定会退出
函数原型:
#include
int pthread_cancel(pthread_t thread);
参数:
pthread_t thread:指定要请求哪个线程退出,填对应的tid号
返回值:
成功,返回0
失败,返回错误码,即非0
注意事项: