目录
1、创建线程
2、线程终止
3、线程等待
4、线程分离
Linux下线程是使用进程模拟实现的,因此没有专门的系统调用来进行线程的各种操作(创建、终止等),Linux下线程控制都是通过POSIX线程库完成的。
1)使用第三方库创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
作用:在该函数被调用的进程中创建一个线程
参数:thread:线程id,输出型参数 attr:暂时不需要关注,设为NULL即可 void *(*start_routine) (void *):参数和返回值均为void*函数指针,即该线程要执行的函数 arg:函数参数
返回值:成功返回0,失败返回错误码
#include
#include
#include
void* fun(void *arg)
{
while(1)
{
printf("i am neww thread!process id : %d\n",getpid());
sleep(1);
}
}
int main()
{
pthread_t pt;
//创建线程
pthread_create(&pt,NULL,fun,NULL);
while(1)
{
printf("i am main thread!process id : %d -- %p\n",getpid(),pt);
sleep(2);
}
return 0;
}
2)线程id和程序地址空间布局
调用pthread_create函数创建线程,会生以输出型参数的形式生成一个线程id,这个线程id用来唯一标识一个线程。通过上述代码输出结果,我们可以看到想爱你城id实际上是一个地址,pthread_ create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID, 属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。线程库提供了pthread_self函数用于获取线程自身id.
pthread_t pthread_self();
在Linux系统中,运行一个多线程程序,使用ps -aL命令可以看到以下信息:
在一个包含两个线程的进程中,两个线程的pid都是相同的,但是除了pid还有一个LWP,表示什么呢?
在Linux中,线程是轻量级进程,LWP表示轻量级进程id,用来唯一标识一个轻量级进程。
3)使用pthread_self查看线程id
pthread_t pthread_self(void);//查看该线程的线程id
4)总结
①什么是LWP
LWP是轻量级进程id。Linux中线程是用进程模拟实现的,创建一个线程在内核中会给该进程创建一个task_struct结构体,而task_struct是进程控制块,因此该进程称为轻量级进程。而LWP就是该轻量进程的id,用来唯一标识一个轻量级进程。
②pthread_create和LWP的关系
pthread_create是由第三方库提供的创建线程的函数,因此该函数不属于系统调用。使用该函数创建线程,需要由第三方库进行管理,而线程的管理也遵循“先描述在组织”的原则。创建线程会在用户区创建相应的数据结构,同时内核中也会为该线程创建task_struct结构体,用户区的数据结构需要通过LWP来找到该结构体实现线程相关的功能。
③轻量级进程id和进程id之间的区别
无论是进程id还是轻量级进程id它们的作用都是标识,在多线程程序中,所有线程的进程id是相同的,而轻量级进程id是不同的。操作系统中调度是以轻量级进程id进行调度的。
进程的终止有三种方式,分别是:main函数中的return;任意位置调用exit;任意位置调用_exit。在线程中,线程的退出也有三种方式:
1)pthread_exit()
void pthread_exit(void *retval);
参数:输出型参数,返回线程的退出状态。当其他线程使用pthread_join等待该想爱你城时,可以通过pthread_join的第二个参数来获取该值。
注意:线程使用return和pthread_exit退出时,返回值必须是全局的或者是malloc分配的,因为当其他线程得到这个返回值时该线程已经退出。
2)pthread_cancel()
int pthread_cancel(pthread_t thread);
参数:要终止的线程id
返回值:成功返回0,失败返回错误码
1)为什么需要线程等待?
2)pthread_join
int pthread_join(pthread_t thread,void **value_ptr);
作用:等待指定id的线程结束,回收该线程的资源
参数:thread:线程id value_ptr:输出型参数
返回值:成功返回0,失败返回错误码
注意
3)三种方法退出一个线程并使用pthread_join等待该线程代码演示
#include
#include
#include
/*
void* route1(void* arg)
{
printf("%s,id : %d\n",(char*)arg,pthread_self());
sleep(1);
//使用return退出
return (void*)0;
}
*/
/*
void* a;
void* route1(void* arg)
{
printf("%s,id : %d\n",(char*)arg,pthread_self());
sleep(1);
//使用pthread_exit退出
a = (void*)10;
pthread_exit(a);
}
*/
void* route1(void* arg)
{
printf("%s,id : %d\n",(char*)arg,pthread_self());
while(1);
}
int main()
{
//创建线程
pthread_t tid;
void* returnValue;
pthread_create(&tid,NULL,route1,"thread route1");
sleep(1);
pthread_cancel(tid);
pthread_join(tid,&returnValue);
printf("%dthread exit,exit code:%d\n",tid,(int*)returnValue);
return 0;
}
默认情况下,创建新线程是joinable的(可重入的),线程退出后需要使用pthread_join操作对该线程的资源进行回收,否则无法回收资源导致资源泄露。如果不关心退出线程的返回值,可以对该线程进行分离,分离的线程退出后会自动释放自己得资源。
int pthread_detach(pthread_t thread);
参数:要分离的线程id
返回值:成功返回0,失败返回退出码(返回值)
注意:线程分离可以是被别的线程分离,也可以是自己对自己进行分离。一个线程要么是joinable,要么是分离的,不可能即是joinble又是分离的(分离和joinable是冲突的)
#include
#include
#include
void* fun(void* arg)
{
//线程自身分离
pthread_detach(pthread_self());
//打印分离成功
printf("detach success,thread id : %d\n",pthread_self());
sleep(3);
return NULL;//不关心返回结果,返回空
}
int main()
{
//创建一个新线程
pthread_t tid;
if(pthread_create(&tid,NULL,fun,NULL) == 0)
printf("create success!\n");
sleep(1);//等待新线程分离
if(pthread_join(tid,NULL) == 0)
printf("wait success!\n");
else
printf("wait fail!quit!!!\n");
return 0;
}