免费开发个人网站,php网站建设英文文献,室内设计用什么软件比较好,wordpress 调用用户头像文章目录 前言#xff1a;为什么要链接pthread库#xff1f;线程控制#xff1a;线程创建#xff1a;start_routine?传递自定义类型同一份栈空间#xff1f; 线程等待#xff1a;返回值与参数#xff1f;创建多线程 线程终止线程分离 前言#xff1a;
上一文我们学习… 文章目录 前言为什么要链接pthread库线程控制线程创建start_routine?传递自定义类型同一份栈空间 线程等待返回值与参数创建多线程 线程终止线程分离 前言
上一文我们学习了解了线程的相关概念我们以生动形象的概念阐释了线程这一具体的概念我们同时也输出了一个重要的结论“线程是CPU调度的基本单位”。在那一刻我们同样也输出了重要的知识在Linux中不存在进程和线程控制块这个区分而针对于LinuxCPU只认轻量级进程而不是什么线程控制块。 那同样进程我们是存在控制的例如创建、删除、等待和替换那么针对于线程我们同样也是要对其进行管理控制的因此本文重点讲解线程控制。
为什么要链接pthread库
在正式讲解线程控制的具体操作我想先来打通一个疑惑就是为什么我们上次在写代码时要在使用g编译的时候加上选项-pthread这个操作的本质是链接pthread库那为什么我要链接它呢
让我们先暂时回到上文还记得我说过Linux本质没有线程的就算你非说有那也只是轻量级进程而我们目前想认为你Linux生成的就是线程所以就有两个概念—— “用户级线程”和“内核级线程”。
很明显这是两个不同的概念而为了将这两个概念打通就不得不提供接口让用户按照普通的方式调用函数使用线程即可也使用户也可以认为自己使用的就是现场同时又可以兼顾Linux系统使用轻量级进程的方法。因此我们就不得不使用pthread库。
线程控制
线程创建
我们使用函数pthread_create 在上一文我们也介绍和粗略的使用过但是我们并没有研究其参数的各种含义下面我们就来介绍和使用。
#include pthread.hint pthread_create(pthread_t *thread, /* 输出型参数用以获取创建成功的线程 ID */const pthread_attr_t *attr, /* 设置创建线程的属性使用 nullptr 表示使用默认属性 */void *(*start_routine) (void *), /* 函数地址该线程启动后需要去执行的函数 */void *arg); /* 线程要去执行的函数的形参没参数时可填写 nullptr */线程创建成功时返回 0创建失败时返回错误码。
start_routine?
这个和我们的当初创建的学习信号中自定义捕捉很像同样是传递一个函数指针但是这里传进来的函数的我们并没有介绍介绍
void* start_routine(void* args)函数呈现的是这样的一种格式这个函数和自定义捕捉的函数一致捕捉到了信号我们就在这个函数里做动作同理创建好线程后这里就是线程执行的地方。举个最简单的例子
// 创建单线程
#include iostream
#include pthread.h
#include unistd.hvoid* start_routine(void* args)
{while(true){sleep(1);std::cout new thread running... std::endl;}
}int main()
{pthread_t tid;pthread_create(tid, nullptr, start_routine, nullptr);while(true){std::cout main thread running... std::endl;sleep(1);}return 0;
}传递自定义类型
要知道我们这两个参数的类型都是void*的这就给了我们很多可能我们不仅仅可以传递普通的类型我们也可以传递结构体/类这大大的提高了我们使用线程的灵活性
#include iostream
#include pthread.h
#include unistd.h
#include stringclass Person
{
public:std::string Print(){return _name : std::to_string(_age);}std::string _name;int _age;
};void* start_routine(void* args)
{Person *tp (Person *)args;std::string info tp-Print();while (true){sleep(1);std::cout new thread running... info std::endl;}
}int main()
{Person p;p._age 20;p._name Eric;pthread_t tid;pthread_create(tid, nullptr, start_routine, p);while(true){std::cout main thread running... std::endl;sleep(1);}return 0;
}同一份栈空间
这里见识到了线程的灵活之处不仅仅可以传递内置类型的数据就连我们的自定义类型的数据我们都能进行传递但是这种做法显然不是很好的。 因为在进行对象实例化的时候对象是在main函数的栈区创建的然后再传递给新线程。换句话说就是主线程与新线程共用了同一个栈空间里的资源这很明显是不对的因为一但我对主线程的对象进行修改新线程同样也会看到并同样也会对其修改造成最终的数据与我们期待的不一致。这个问题通常会发生在创建多线程时当我需要修改原来的对象然后传递给新线程2的时候因此我们在这里不得不停下来好好思考思考。 在这里先对代码进行了修改
#include iostream
#include pthread.h
#include unistd.h
#include stringclass Person
{
public:std::string Print(){return _name : std::to_string(_age);}std::string _name;int _age;
};void* start_routine(void* args)
{while(true){sleep(1);Person *tp (Person *)args;std::string info tp-Print();std::cout new thread running... info std::endl;}
}int main()
{Person p;p._age 20;p._name Eric;pthread_t tid;pthread_create(tid, nullptr, start_routine, p);std::cout ready to change data std::endl;sleep(3);// 修改数据p._name Alan;p._age 18;std::cout data changed std::endl;sleep(30); // 这里我简化了其实应该是释放新线程再退出主线程好一点。return 0;
}这个错误不是没有解决办法的我们要解决的就是主线程用自己的空间新线程也用自己的空间那很好办直接在各自的堆上new一个就好了。这样就算你创建了两个新线程这两个线程的数据也是在堆空间上独立的
线程等待
当然和之前进程一样主线程也是要等待新线程的结束然后回收资源这当然也是避免一种类似“僵尸进程”的情况但是线程提供的接口我们又能做很多工作下面我们就来看看看线程等待的具体操作。 首先认识接口函数pthread_join
#include pthread.hint pthread_join(pthread_t thread, /* 被等待的线程的线程 ID */ void **retval); /* 获取被等待的线程在退出时的返回值 */与进程不同的是这里的线程等待默认就是阻塞等待直到所等待的的新线程终止为止。 同样的是等待成功会返回0否则返回对应的错误码而这个错误码并不与进程等待失败的那个位图一致。
测试一下
#include iostream
#include pthread.h
#include unistd.hvoid *start_routine(void* args)
{int cnt 5;while(cnt){std::cout new thread running... cnt: cnt std::endl;--cnt;sleep(1);}return nullptr;
}int main()
{std::cout main thread running... std::endl;pthread_t tid;pthread_create(tid, nullptr, start_routine, nullptr);int n pthread_join(tid, nullptr);if(n 0){std::cout wait suceess! std::endl;}else{std::cout wait failed.... std::endl;}return 0;
}返回值与参数
我们在刚刚的初次使用上并没有研究第二个参数retval而这里要注意它的类型是void**而它的作用是用来接收被等待的线程结束时的返回值那么我们就可以浅浅的试一试使用它
#include iostream
#include pthread.h
#include unistd.h
#include stringvoid *start_routine(void* args)
{int cnt 5;while(cnt){std::cout new thread running... cnt: cnt std::endl;--cnt;sleep(1);}return (void*)thread done; // 返回一个stirng类型
}int main()
{std::cout main thread running... std::endl;// 线程创建pthread_t tid;pthread_create(tid, nullptr, start_routine, nullptr);// 线程等待void *ret nullptr; // 用来接收线程结束时的返回值int n pthread_join(tid, ret);std::string r (const char *)ret; // 强制类型转换获得返回值的合适类型if (n 0){std::cout wait suceess! std::endl;std::cout new thread return: “ r ” std::endl;}else{std::cout wait failed.... std::endl;}return 0;
}同样的我们也可以对自定义类型进行传参比如这里我还是创建Person类但是我这里只是new一个而不对其进行初始化相当于直接传递了一个“空类”然后我们在新创建的线程中对这个“空类”进行初始化然后我们返回这个类看看我们是否能读取出来
#include iostream
#include pthread.h
#include unistd.h
#include stringclass Person
{
public:std::string _name;int age;
};void *start_routine(void* args)
{int cnt 5;while(cnt){std::cout new thread running... cnt: cnt std::endl;--cnt;sleep(1);}// 设置对象的数据并返回Person* pt (Person*)args;pt-_name Carl;pt-age 19;return (void *)pt;
}int main()
{std::cout main thread running... std::endl;// new实例化对象Person *p new Person;// 创建线程pthread_t tid;pthread_create(tid, nullptr, start_routine, p);void *ret nullptr; // 用来接收线程结束时的返回值int n pthread_join(tid, ret);Person *r (Person *)ret; // 强制类型转换获得返回值的合适类型if (n 0){std::cout wait suceess! std::endl;std::cout new thread return: “ r-_name : r-age ” std::endl;}else{std::cout wait failed.... std::endl;}return 0;
}创建多线程
结合已有的知识我们已经完全具备创建多线程然后在主线程结束之前回收这些多线程比如现在我想创建10个线程然后各个线程去打印一段话就好了最后再一次返回主线程依次等待回收。
#include iostream
#include pthread.h
#include unistd.h
#include string
#include vectorconst pthread_t num 10;
void *start_routine(void *args)
{std::string tt (const char *)args;std::cout tt is running... std::endl;sleep(1);return args;
}int main()
{// 创建线程std::vectorpthread_t tids;for (int i 1; i num; i){char *name new char[128];snprintf(name, 128, thread_%d, i);pthread_t tid;pthread_create(tid, nullptr, start_routine, name);tids.push_back(tid);}// 回收线程for (int i 0; i tids.size(); i){void *ret nullptr;pthread_join(tids[i], ret);char *r (char *)ret;std::cout r quit... std::endl;}return 0;
}线程终止
如果只是想终止某个线程而不是整个进程可以有如下 3 种方法。
使用 return 终止线程非主线程可以在执行的函数中使用 return 终止当前线程。使用 pthread_exit 终止线程线程自己可以调用该函数终止自己。使用 pthread_cancel 终止线程该函数能通线程 ID 终止任意线程。
切记你最好不要用exit(1)这样的方式终止线程因为这不仅仅会终止线程还会直接终止掉你的进程这个必须要额外注意
线程分离
默认情况下新创建的线程是joinable的线程退出后需要对其进行pthread_join操作否则无法释放 资源从而造成系统泄漏。如果不关心线程的返回值join是一种负担这个时候我们可以告诉系统当线程退出时自动释放线程资源。
#include pthread.hint pthread_detach(pthread_t thread); // thread 是要分离出去的线程的 ID可以是线程组内其他线程对目标线程进行分离也可以是线程自己分离: pthread_detach( pthread_self() );
注意这里的pthread_self()是获取自己线程的ID哪个线程调用这个函数就返回哪个线程的ID pthread_self 函数获得的线程 ID 不等于内核的 LWP 值pthread_self 函数获得的是用户级原生线程库的线程 ID而 LWP 是内核的轻量级进程ID它们之间是一对一的关系。 后续我们会逐一展开 **一个线程要是被分离了那么该线程就是处于分离状态是不能被join的但是依旧属于进程内部只是不再需要被等待了**joinable和分离是冲突的一个线程不能既是joinable又是分离的。
虽然分离出去的线程已经不归主线程管了但一般还是建议让主线程最后再退出。分离出去的线程可以被 pthread_cancel 函数终止但不能被 pthread_join 函数等待。一个线程可以将其他线程分离出去也可以将自己分离出去。 文章转载自: http://www.morning.cptzd.cn.gov.cn.cptzd.cn http://www.morning.zrqs.cn.gov.cn.zrqs.cn http://www.morning.qwdqq.cn.gov.cn.qwdqq.cn http://www.morning.wjtxt.cn.gov.cn.wjtxt.cn http://www.morning.zylzk.cn.gov.cn.zylzk.cn http://www.morning.lkrmp.cn.gov.cn.lkrmp.cn http://www.morning.qmpbs.cn.gov.cn.qmpbs.cn http://www.morning.kbfzp.cn.gov.cn.kbfzp.cn http://www.morning.frfpx.cn.gov.cn.frfpx.cn http://www.morning.nfbkp.cn.gov.cn.nfbkp.cn http://www.morning.rpwm.cn.gov.cn.rpwm.cn http://www.morning.twmp.cn.gov.cn.twmp.cn http://www.morning.hqlnp.cn.gov.cn.hqlnp.cn http://www.morning.rnzbr.cn.gov.cn.rnzbr.cn http://www.morning.xqwq.cn.gov.cn.xqwq.cn http://www.morning.qlhkx.cn.gov.cn.qlhkx.cn http://www.morning.tcfhs.cn.gov.cn.tcfhs.cn http://www.morning.bmqls.cn.gov.cn.bmqls.cn http://www.morning.pqfbk.cn.gov.cn.pqfbk.cn http://www.morning.tfrlj.cn.gov.cn.tfrlj.cn http://www.morning.mtqqx.cn.gov.cn.mtqqx.cn http://www.morning.sqqpb.cn.gov.cn.sqqpb.cn http://www.morning.nzqqd.cn.gov.cn.nzqqd.cn http://www.morning.sqmbb.cn.gov.cn.sqmbb.cn http://www.morning.pinngee.com.gov.cn.pinngee.com http://www.morning.bftqc.cn.gov.cn.bftqc.cn http://www.morning.rgnp.cn.gov.cn.rgnp.cn http://www.morning.kxgn.cn.gov.cn.kxgn.cn http://www.morning.tmfhx.cn.gov.cn.tmfhx.cn http://www.morning.qwnqt.cn.gov.cn.qwnqt.cn http://www.morning.xrwbc.cn.gov.cn.xrwbc.cn http://www.morning.zzqgc.cn.gov.cn.zzqgc.cn http://www.morning.fhcwm.cn.gov.cn.fhcwm.cn http://www.morning.ghccq.cn.gov.cn.ghccq.cn http://www.morning.rjrh.cn.gov.cn.rjrh.cn http://www.morning.yrxcn.cn.gov.cn.yrxcn.cn http://www.morning.zlcsz.cn.gov.cn.zlcsz.cn http://www.morning.ztqj.cn.gov.cn.ztqj.cn http://www.morning.mswkd.cn.gov.cn.mswkd.cn http://www.morning.dzyxr.cn.gov.cn.dzyxr.cn http://www.morning.fhddr.cn.gov.cn.fhddr.cn http://www.morning.krjyq.cn.gov.cn.krjyq.cn http://www.morning.lpcct.cn.gov.cn.lpcct.cn http://www.morning.dndk.cn.gov.cn.dndk.cn http://www.morning.qtsks.cn.gov.cn.qtsks.cn http://www.morning.mbnhr.cn.gov.cn.mbnhr.cn http://www.morning.npfrj.cn.gov.cn.npfrj.cn http://www.morning.kxnjg.cn.gov.cn.kxnjg.cn http://www.morning.dbhnx.cn.gov.cn.dbhnx.cn http://www.morning.kwwkm.cn.gov.cn.kwwkm.cn http://www.morning.mpszk.cn.gov.cn.mpszk.cn http://www.morning.qlry.cn.gov.cn.qlry.cn http://www.morning.pttrs.cn.gov.cn.pttrs.cn http://www.morning.dbjyb.cn.gov.cn.dbjyb.cn http://www.morning.flchj.cn.gov.cn.flchj.cn http://www.morning.nxfuke.com.gov.cn.nxfuke.com http://www.morning.ypbp.cn.gov.cn.ypbp.cn http://www.morning.banzou2034.cn.gov.cn.banzou2034.cn http://www.morning.pgkpt.cn.gov.cn.pgkpt.cn http://www.morning.zqmdn.cn.gov.cn.zqmdn.cn http://www.morning.pxwzk.cn.gov.cn.pxwzk.cn http://www.morning.bmsqq.cn.gov.cn.bmsqq.cn http://www.morning.cwskn.cn.gov.cn.cwskn.cn http://www.morning.qgfy.cn.gov.cn.qgfy.cn http://www.morning.gklxm.cn.gov.cn.gklxm.cn http://www.morning.mkczm.cn.gov.cn.mkczm.cn http://www.morning.mslsn.cn.gov.cn.mslsn.cn http://www.morning.xnnxp.cn.gov.cn.xnnxp.cn http://www.morning.cnprt.cn.gov.cn.cnprt.cn http://www.morning.hlshn.cn.gov.cn.hlshn.cn http://www.morning.lyldhg.cn.gov.cn.lyldhg.cn http://www.morning.dthyq.cn.gov.cn.dthyq.cn http://www.morning.rntyn.cn.gov.cn.rntyn.cn http://www.morning.xgmf.cn.gov.cn.xgmf.cn http://www.morning.bcdqf.cn.gov.cn.bcdqf.cn http://www.morning.tgnr.cn.gov.cn.tgnr.cn http://www.morning.nkpls.cn.gov.cn.nkpls.cn http://www.morning.zcqgf.cn.gov.cn.zcqgf.cn http://www.morning.zgdnd.cn.gov.cn.zgdnd.cn http://www.morning.mgwpy.cn.gov.cn.mgwpy.cn