最近在用c++实现一个p2p文件传输的程序,用c++实现基本的工具类,供c#(c++/clr,wpf框架,工具visual studio)和java(jni技术,工具android studio)调用实现界面,在这个过程中不免要用到多线程技术。
在这里记录一下学习的过程,以后可以回顾。
之前课程设计曾经做过一个http多线程下载,用的是mfc框架,不得不说 不追求界面的话勉强可以用。
首先引入头文件 thread,实例化thread类对象时,至少要传入函数名作为参数,若传入的函数具有参数,则要在传入的函数后加上参数,若参数是可引用的则实例化之后,这个线程就会被创建并运行
thread类中提供了这两个方法。通常是在其他线程中,调用该线程对象的join 和detach 方法,意思是挂起当前线程a,等调用此方法的对象对应的线程执行结束后再继续。可以用joinable()来判断是否可以调用join()和detach()。
a.在哪个线程调用,哪个线程就被挂起,这个线程不是调用该方法的线程对象对应的线程。问题:如果在自己的线程中调用自己的join和detach方法会怎样?
一般在某段代码里可能触发竞争时,在这段代码之前调用lock,执行完后再unlock。就好像高铁上上厕所,谁先进厕所就lock,用完之后就unlock,其他人(线程)等待时就一直判断有没有unlock(调用lock之后进入阻塞状态,不断判断有没有unlock)。
metex m;
lock_guard<mutex> lg(m)
将metex对象封装进lock_guard类中,相当于执行了lock(),并且在作用域结束后自动unlock()。
需要手动lock()和unlock(). 且多了其他用法
需要引入#include<condition_variable>, 且 配合mutex使用
condition_variable类提供了notify_one()和wait(unique_lock ul)方法,其中wait(ul)用来锁住当前线程,等相同condition_variable对象调用notify_one()时,线程被唤醒。
wait还有一个重载函数,多了第二个bool型参数,当调用wait时该参数为false才会阻塞当前线程,当其他线程发起notify时该参数为true时才会解除阻塞。
future: future<double> fu = async(function f,parameter a,~);
可以通过调用fu.get()来获取函数返回值,调用时函数可以未执行完,并且在函数返回前,调用get()的线程阻塞。get只能调用一次
shared_future: get()可以调用多次
atomic<> v
mutex用来给一段操作上锁,而atomic是给一个变量上锁,某个变量被上锁后,其他线程要改变该变量的操作将被阻塞,注意这里的上锁解锁行为是atomic自动实现的,即先使用者 使用后会自动上 锁,后使用者在先使用者使用完后才能对变量进行操作。使用atomic时直接对atomic对象操作代替对原变量的操作。
三.线程池
这里只谈一下实现线程池的主要思想。
1.线程池顾名思义含有一个线程队列1,在没有任务需要执行时这些线程处于阻塞状态,因此实例化线程池对象时需要创建一些线程并使得他们处于阻塞状态。
2.在有任务进来时某个线程执行这个任务,线程池提供一个添加任务的方法2,涉及函数对象的传递,并且需要维护一个任务列表3。
3.那么这些阻塞的线程怎样才能知道有任务来了呢,这里可以使用condition_variable4,线程刚运行时调用wait,并且这里用到两个参数的wait方法,这样的话只有获得任务的线程才会取消阻塞状态。
4.在实例化线程池对象后,我们所需要做的就是告诉线程池需要执行的任务,线程池在接收到任务后会调用notify唤醒线程,由线程主动获得某个任务,并且要从线程池任务列表中删去这个任务,这又涉及锁,一次只允许一个线程对列表进行操作。
综上,要实现的东西:1.线程列表,任务列表
2.添加任务的函数:实现任务入队(对任务队列的添加操作 加锁),唤醒线程。
3.线程中要实现的操作:阻塞自己,被唤醒之后(只有任务队列有任务存在才会被唤醒)获取任务,在任务队列中删除该任务(加锁),继续阻塞
资料来源:https://zhuanlan.zhihu.com/p/194198073 作者:zizbee
原文:https://www.cnblogs.com/hyh2050/p/14260176.html