网站如何做cdn,黔西南建设厅网站,买高端品牌网站建设,WordPress留言板dux1、多线程相关概念
1.1 并发、并行、串行
并发#xff08;Concurrent#xff09;#xff1a;并发是指两个或多个事件在同一时间间隔内运行。在操作系统中#xff0c;是指一个时间段中有几个程序都处于已启动运行到运行完毕之间#xff0c;且这几个程序都是在同一个处理机…1、多线程相关概念
1.1 并发、并行、串行
并发Concurrent并发是指两个或多个事件在同一时间间隔内运行。在操作系统中是指一个时间段中有几个程序都处于已启动运行到运行完毕之间且这几个程序都是在同一个处理机上运行。 同一时刻只能有一条指令执行但多个进程指令被快速的轮换执行使得在宏观上具有多个进程同时执行的效果但在微观上并不是同时执行的只是把时间分成若干段使多个进程快速交替的执行。
并行Parallel并行是指两个或者多个事件在同一时刻运行。当系统有一个以上CPU时当一个CPU执行一个进程时另一个CPU可以执行另一个进程两个进程互不抢占CPU资源可以同时进行这种方式我们称之为并行(Parallel)。其实决定并行的因素不是CPU的数量而是CPU的核心数量比如一个CPU多个核也可以并行。如下图所示。当线程数超过cpu核心数时部分线程变成了并发执行。 串行并行和串行指的是任务的执行方式。并行指的是多个任务可以同时执行 。串行是指多个任务时各个任务按顺序执行完成一个之后才能进行下一个它们在时间上是不可能发生重叠的。如下图所示
1.2 同步、异步
阻塞(blocking)、非阻塞non-blocking可以简单理解为需要做一件事能不能立即得到返回应答如果不能立即获得返回需要等待那就阻塞了(进程或线程就阻塞在那了不能做其它事情)否则就可以理解为非阻塞(在等待的过程中可以做其它事情)。
同步(synchronous) 是指一个进程在执行某个请求的时候若该请求需要一段时间才能返回信息那么这个进程将会一直等待下去直到收到返回信息才继续执行下去; 同步是阻塞模式其相当于单线程中的串行模式 同步就相当于是 当客户端发送请求给服务端在等待服务端响应的请求时客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。
异步(asynchronous)是指进程不需要一直等下去而是继续执行下面的操作不管其他进程的状态。当有消息返回时系统会通知进程进行处理这样可以提高执行的效率。 异步是非阻塞模式多线程都是异步的 异步就相当于当客户端发送给服务端请求时在等待服务端响应的时候客户端可以做其他的事情这样节约了时间提高了效率
1.3 进程、线程
进程Process是正在运行的程序实体并且包括这个运行的程序中占据的所有系统资源比如说CPU寄存器IO,内存网络资源等。同样一个程序同一时刻被两次运行了那么他们就是两个独立的进程。
线程Thread是操作系统能够进行运算调度的最小单位。它被包含在进程之中是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流一个进程中可以并发多个线程每条线程并行执行不同的任务。
进程与线程的区别
线程是程序执行的最小单位而进程是操作系统分配资源的最小单位进程是系统资源分配的单位线程是系统调度的单位。一个进程由一个或多个线程组成线程是一个进程中代码的不同执行路线进程之间相互独立进程之间不能共享资源而一个进程内的线程可以共享所在进程的地址空间和其它资源。同时线程还有自己的栈和栈指针程序计数器等寄存器。调度和切换速度线程上下文切换其包含共享资源比进程上下文切换其不包含共享资源要快得多。
1.4 多线程
多线程是指程序中包含多个执行流即在一个程序中可以同时运行多个不同的线程来执行不同的任务。每个线程都有自己的专有寄存器如栈指针、程序计数器但代码区是共享的即不同的线程可以执行同样的方法。多线程技术允许单个程序创建多个并行执行的线程来完成各自的任务从而提高整体的处理性能。
多线程是一种机制允许在程序中并发执行多个指令流每个指令流都称为一个线程彼此间互相独立。线程与进程相似但线程更为轻量级并且专注于执行单一的任务。多线程是多任务的特殊形式它能够提高系统的效率特别是在需要同时完成多项任务的情况下。
以上内容参考自 https://blog.csdn.net/wang121213145/article/details/123828346
2、多线程编程关键知识
2.1 如何创建线程
1. 创建线程的一般方法 说明
主线程从main开始执行一旦主线程从main()返回则整个程序进程结束如果主线程结束了其他子线程还没执行完一般会被操作系统强行终止除非子线程设置为detach通常我们创建的子线程从一个函数开始运行一旦此函数运行完毕代表这个线程运行结束如果想保持子线程一直运行不要让主线程运行完毕除非子线程设置为detach
2.创建子线程的一般方法
包含头文件#include thread编写一个子线程开始执行的函数初始函数使用thread()创建子线程设置主线程和子线程的关系join()或detach()join() 表示子线程会阻塞主线程的运行detach()单独运行
2.1.1 thread)
1先看一个示例这里子线程myprint和主线程main并发运行
#include iostream
#include thread
#includewindows.h
using namespace std;//子线程的初始函数
void printThread(int theadId)
{cout 我的线程开始执行: theadId endl;Sleep(1000);cout 我的线程执行完毕 endl;
}//主线程在从main开始执行一旦主线程从main()返回则整个程序结束
int main()
{//创建子线程这两行在main函数里int theadId100;thread thread1(printThread,theadId); //创建了线程执行起点是printThread同时让子线程开始执行thread1.join(); //主线程阻塞在这里等子线程执行完。如果不加join主线程结束了子线程还在运行会导致程序崩溃cout Hello World!\n; return 0;
}-----运行结果-------- 我的线程开始执行:100
我的线程执行完毕
Hello World!\n2关于thread thread是一个类 thread thread1(printThreadtheadId);是利用构造函数创建了thread对象传入参数是一个函数名称及对应函数的参数 这行代码创建了一个线程对象执行起点是printThread函数入口并启动了子线程。 C11 functional对函数指针做了拓展可调用对象包括函数指针和函数对象等
2.1.2 join() join 是 thread 类中的一个方法 作用阻塞主线程其不会阻塞子线程让主线程等待子线程执行完毕然后子线程和主线程汇合再往下执行 如果把上面的thread1.join();注释掉可能会看到输出混乱在部分电脑上会直接引发报错因为主线程线运行结束了而且弹出异常提示 (1) 由于主线程和子线程交替执行所以打印混乱 (2) 由于子线程没有结束主线程就结束了子线程被操作系统强制结束所以报异常 一旦把线程join了就不能再detach了否则报异常我们自己来控制子进程 如果主线程执行完毕了但是子线程没有执行完毕这种程序是不稳定的所以我们应该尽量保证主线程在所有子线程运行结束后再结束。
2.1.3 detach()
传统多线程程序主线程要等待所有子线程执行完再退出但C11增加了detach()可以不这样干了 detach 是 thread 类中的一个方法 作用将子线程和主线程分离分离后的子线程与主线程没有关联主线程结束后如果子线程还没有结束那么会在后台继续运行当子线程执行完毕后由运行时库负责清理该线程相关资源 一旦把线程detach了就不能再join回来了否则报异常我们失去了对这个进程的控制。
thread thread1(printThread);
thread1.detach();2.1.4 joinable() joinable 是 thread 类中的一个方法 作用用来判断线程是否可以成功使用join 和 detch 返回值 True可以进行join()或detach()False不能进行join()或detach()在 进行join()或者detach()操作时先进行判断然后再操作
thread thread1(printThread);
if (thread1.joinable())
{thread1.join();
}这样可以避免系统报错
以上内容参考自https://blog.csdn.net/wxc971231/article/details/105979443
2.2 线程间变量同步
C线程间线程间变量同步使基于共享内存是实现的即多个线程使用同一个变量名在线程a访问变量时可能存在线程b正在修改变量的情况故需要设置线程安全机制。
1.互斥锁Mutex互斥锁是一种同步机制用于防止多个线程同时访问共享资源。主要方法包括两个分别是 Lock 和 Unlock。当一个线程获得互斥锁时其他线程将被阻塞直到该线程释放锁。互斥锁的优点是可以避免死锁缺点是可能会导致线程饥饿。
2.条件变量Ondition variable条件变量是一种同步机制用于在多个线程之间传递信号。当一个线程等待某个条件时它可以调用条件变量的wait()方法来阻塞自己。 while (workq NULL), 其workq为条件变量通过while 死循环阻塞程序向后运行 通过条件变量可以一次性阻塞或者激活多个线程
3.信号量Semaphore信号量是一种同步机制用于控制对共享资源的访问。当一个线程需要访问共享资源时它必须先获取信号量。如果信号量的值为0则线程将被阻塞直到另一个线程释放信号量。其本质是通过一个变量来控制多个线程的运行当变量值为n时表示允许运行n个线程每运行一个线程值减1当n为0时表示没有资源可供线程运行当值为-n时表示n个线程在等待运行当线程运行结束n的值则加一表示释放一个线程执行机会 信号量的优点是可以避免死锁和线程饥饿缺点是可能会导致信号量竞争。从实现上来说一个信号量可以是用mutex counter condition variable
4.管道Pipe管道是一种进程间通信机制但也可以用于线程间通信。管道是一个字节流可以用于在两个线程之间传递数据。管道的优点是简单易用缺点是只能用于有亲缘关系的线程之间通信。 具体可以参考https://blog.csdn.net/skyroben/article/details/71513385
3、基于面相对象的多线程类使用
在多线程操作中常见的问题是生产者-消费者问题生产者用于生成数据消费者用于处理数据二者间通过共用一个变量进行信息交互。 前文所提到的线程创建方法为基于函数的在实际使用过程中以面向对象进行开发需要将函数相关的功能封装成class。在面向对象中多线程类也可以通过std::thread进行实现具体可以参考以下代码。
其GetImage为生产者DealImage为消费者imglist为两者间的共享变量mtx为互斥锁。 #include iostream
#include thread
#include windows.h
#include opencv2/opencv.hpp
using namespace std;
using namespace cv;using namespace std;
std::mutex mtx; // 保护对imglist的访问
vectorMat imglist;
//------------获取图像的线程类imglist的元素在增多---------------
class GetImage
{
public:GetImage(vectorMat imglist);void startWork();void work();static void threadFunc(GetImage*);
};GetImage::GetImage(vectorMat imglist) {
}void GetImage::work()
{int count 0;while (1){Mat mat;mtx.lock();imglist.push_back(mat);mtx.unlock();cout 容器内数据量: imglist.size() endl;Sleep(300);}
}void GetImage::threadFunc(GetImage* arg)
{arg-work();
}void GetImage::startWork()
{std::thread work_thread(threadFunc, this);work_thread.detach();
}//------------处理图像的线程类imglist的元素在减少---------------
class DealImage
{
public:DealImage(vectorMat DealImage);void startWork();void work();static void threadFunc(DealImage*);
};DealImage::DealImage(vectorMat imglist) {
}
void DealImage::work()
{int count 0;while (1){if (imglist.size() 0) {Mat mat imglist[imglist.size()-1];//获取最后一个元素cout 获取到一张图片 ,剩余图像 imglist.size() - 1 endl;mtx.lock();imglist.pop_back();//删除最后一个元素mtx.unlock();//---这里写图像处理函数---}else {cout --------没有获取到一张图片-------- endl;}Sleep(400);}
}void DealImage::threadFunc(DealImage* arg)
{arg-work();
}void DealImage::startWork()
{std::thread work_thread(threadFunc, this);work_thread.detach();
}int main()
{GetImage* t1 new GetImage(imglist);t1-startWork();DealImage* t2 new DealImage(imglist);t2-startWork();while (1){Sleep(1);}return 0;
}