分享缩略图

分享到:
链接已复制
首页> 新闻中心>

Linux线程管理进阶:分离,等待、终止与C++11线程接口的封装实践

2025-06-24 11:49:22

来源:新华网

字体:

🍑个人主页:Jupiter.
🚀 所属专栏:Linux从入门到进阶
欢迎大家点赞收藏评论😊

在这里插入图片描述

在这里插入图片描述

目录

      • `🍑线程终止`
      • `🍍线程等待`
            • *多线程创建,传自己定义的对象示例代码:*
    • `🍎线程的分离`
      • `🍌对C++11中线程的代码实现`


🍑线程终止

如果需要只终止某个线程而不终止整个进程,可以有三种方法:

  1. 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
  2. 线程可以调用pthread_ exit终止自己。
  3. 一个线程可以调用pthread_ cancel终止同一进程中的另一个线程
  • 其中,主线程退出==进程退出,该进程的所有线程全部退出。
  • 其中,不能调用exit来终止线程,因为任何一个线程调用exit都会使整个进程退出。

注意:多线程中,任何一个线程出了异常,都会导致整个进程退出。— 多线程代码往往健壮性不好

pthread_exit函数

  • 功能:线程终止
  • 原型
    • void pthread_exit(void *value_ptr);
  • 参数
    • value_ptr:value_ptr不要指向一个局部变量。
    • 返回值:无返回值
      需要注意:调用pthread_exit后,类似return ,即 pthread_exit((void*)100) == return (void *)100 ,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

pthread_cancel函数

  • 功能:取消一个执行中的线程
  • 原型
    • int pthread_cancel(pthread_t thread);
  • 参数
    • thread:线程ID
    • 返回值:成功返回0;失败返回错误码

🍍线程等待

已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
创建新的线程不会复用刚才退出线程的地址空间。

  • 功能:等待线程结束
  • 原型
    • int pthread_join(pthread_t thread, void **value_ptr);
  • 参数
    • thread:线程ID
    • value_ptr:它指向一个指针,后者指向线程的返回值
    • 返回值:成功返回0;失败返回错误码

调用该函数的线程将挂起等待,直到id为thread的线程终止(阻塞等待)。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

  • 如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值。
  • 如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数PTHREAD_ CANCELED((void *) -1)
  • 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。
  • 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数。
  • 注意:pthread_join,不考虑出现异常的情况,因为线程异常,整个进程都结束了,主线程没有pthread_join的机会。

示例代码:

std::string ToHex(pthread_t tid)//将id转换为十六进制{ charbuff[64];snprintf(buff,64,"0x%lx",tid);returnbuff;}void*routine(void*name){ intcnt =5;while(cnt--){ sleep(1);std::cout <<"i am new thread,name:"<<(char*)name <<"  my tid is :"<<ToHex(pthread_self())<<std::endl;}returnvoid*100;}intmain(){ pthread_t tid;pthread_create(&tid,nullptr,routine,(void*)("thread-1"));void*ret =nullptr;intn =pthread_join(tid,&ret);std::cout<<"new thread exit,n = "<<n <<"get a return val:"<<(lont lont)ret<<std::endl;return0;}

在这里插入图片描述

多线程创建,传自己定义的对象示例代码:
#include#include#include#include#include#include#definethreadnum5// 线程执行的任务classTask{ public:Task(intx =10,inty =15):_x(x),_y(y){ }intexcute(){ return_x +_y;}~Task(){ }private:int_x;int_y;};// 存储线程执行结果classResult{ public:Result(intresult,std::string name):_result(result),_name(name){ }voidPrint(){ std::cout <<_name <<" Task result is "<<_result <<std::endl;}~Result(){ }private:int_result;std::string _name;};// 存储线程香相关数据classthreadDate:publicTask{ public:threadDate(intx,inty,conststd::string &name):_name(name),_t(Task(x,y)){ }std::string name(){ return_name;}intResult(){ return_t.excute();}~threadDate(){ }private:std::string _name;Task _t;};// 线程执行的函数void*threadrun(void*argc){ threadDate *td =static_cast<threadDate *>(argc);sleep(1);Result *Res =newResult(td->Result(),td->name());deletetd;returnRes;}intmain(){ // 1.创建多线程std::vector<pthread_t>threads;for(inti =0;i <threadnum;i++){ char*name =newchar[64];snprintf(name,64,"thread-%d",i +1);// 2.参数设置threadDate *td =newthreadDate(10,15,name);pthread_t tid;pthread_create(&tid,nullptr,threadrun,td);threads.push_back(tid);//将线程的tid存放到一个vector中,便于等待}// std::vector threadRes;   //将结果的结构体放到vector中void*Res =nullptr;// 等待线程,并取task结果for(auto&tid :threads){ pthread_join(tid,&Res);((Result *)Res)->Print();// threadRes.push_back((Result *)Res);  //push_back进vector}// 打印结果//  for (auto &Res : threadRes)//  { //      Res->Print();//  }return0;}

🍎线程的分离

  • 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
  • 如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。

int pthread_detach(pthread_t thread);

可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离:

pthread_detach(pthread_self());

joinable和分离是冲突的,一个线程不能既是joinable又是分离的。

注意:如果你尝试对已经分离的线程(包括通过 pthread_self() 获取的当前线程)调用 pthread_join(),通常会导致未定义行为,但在大多数实现中,它会立即返回一个错误,通常是 EINVAL(表示无效参数)。分离只是不需要等待,底层依旧属于同一个进程

示例代码:

#include#include#include#include#include#includevoid*threadrun(void*args){ //pthread_detach(pthread_self()); // 将pthread_self()线程与其他线程分离开std::string name =static_cast<char*>(args);intcnt =5;while(cnt--){ std::cout <<"i am "<<name <<std::endl;sleep(1);}returnnullptr;}intmain(){ pthread_t tid;pthread_create(&tid,nullptr,threadrun,(void*)"thread -1");pthread_detach(tid);//将指定tid的线程分离intn =pthread_join(tid,nullptr);std::cout <<"main thread wait return:"<<n <<":"<<strerror(n)<<std::endl;return0;}

🍌对C++11中线程的代码实现

理解下面代码threadrun函数需要设置为static的原因,以及传入this的原因。

  • 因为pthread_create(),要求传入的函数参数为void *,如果不将函数设置为static,则参数会有一个this指针,所以需要设置static,那为什么要传入this指针呢?因为static成员函数没有this指针,但是func() 的调用需要this指针;
#ifndef__THREAD_HPP__#define__THREAD_HPP__#include#include#include#includenamespaceThreadModule{ template<classT>usingfunc_t =std::function<void(T&)>;// typedef std::function func_t;template<classT>classThread{ public:Thread(func_t<T>func,T&data,std::string name):_func(func),_data(data),_name(name),_stop(true){ }voidexecute(){ _func(_data);}staticvoid*threadrun(void*args){ Thread *self =static_cast<Thread*>(args);self->execute();returnnullptr;}boolstart(){ intn =pthread_create(&_tid,nullptr,threadrun,this);if(!n){ _stop=false;returntrue;}else{ returnfalse;}}voidstop(){ if(!_stop)_stop=true;}voiddetach(){ if(!_stop)pthread_detach(_tid);}std::string &name(){ return_name;}voidjoin(){ if(!_stop)pthread_join(_tid,nullptr);}~Thread(){ }private:pthread_t _tid;func_t<T>_func;T&_data;std::string _name;bool_stop;};}#endif

【责任编辑:新华网】
返回顶部