OpenCV学习 day6 多线程

 第八章

线程与进程的区别:

        进程与单个程序类似,可以由操作系统直接执行;

        线程是进程的一个子集,也就是一个进程可包含多个线程;

        通常情况下,不同的进程彼此是无关的,而不同的线程共享内存和资源(进程可以通过操作系统提供的手段实现彼此交互)

8.1 Qt中的多线程 

        Qt提供的命名空间、类和函数:

        QThread:所以线程的基类,可以从他的派生子类创建新的线程

        QThreadPool:可以用于管理线程,并且可以重用已有线程来实现新的功能

        QRunnable:提供创建线程的另一种方法,

        QMutex、QMutexLocker、QSemaphore、QWaitCondition、QReadLocker、QWriteLocker和QWriteLocker:处理线程间到的同步任务

        QtConcurrent:一个命名空间,可用于高级API创建多线程应用程序

        Qfuture、QfutureQatcher、Qfututelterator和QFutureSynchronizer:这些类与QtConcurrent命名空间共同使用,可以处理多线程以及异步操作结果

8.2 利用QThread实现低级多线程

        通过利用Qt中可用的两种不同方法来使用QThread类,首先子类化并重写run方法,然后使用所有的Qt对象中可用的moveToThread函数。

8.2.1 子类化QThread

class VideoProcessorThread : public QThread
{
    Q_OBJECT
public:
    explicit VideoProcessorThread(QObject *parent = nullptr);

signals:

    void inDisplay(QPixmap pixmap);
    void outDisplay(QPixmap pixmap);

public slots:

private:
    void run() override;

};

注意run函数只能在内部调用,因此只需重新实现它,用到以下函数:

        start:用于启动一个未启动的线程

        terminate:强制终止线程,(不推荐使用)

        setTerminationEnable:可用于允许或禁止terminate

        wait:该函数用于阻塞线程(强制等待),直到线程完成或者达到超时值

        requestInterruption和isRequestInterrupted:可以用于设置和获取中断请求状态

        isRunning和isFinished:请求线程的执行状态

然后在MainWindow中使用线程,包含头文件,然后再私有成员里面添加

VideoProcessorThread processor;

 连接信号,放在构造函数中,setupUi代码前

connect(processor, SIGNAL(inDisplay(QPixmap)),
              ui->inVideo, SLOT(setPixmap(QPixmap)));

processor.start();

 在MainWindow的析构函数中,delete ui之前,

processor.requestInterruption();

processor.wait();

 8.2.2 使用moveToThread函数

        使用moveToThread函数可以确保它在一个单独的线程中运行。

processor = new VideoProcessor();

processor->moveToThread(new QThread(this));

然后使用startVideo和stopVideo函数用来启动和终止对来自默认摄像头的处理

//构造函数中

    processor->thread()->start();

//析构函数中

    processor->stopVideo();
    processor->thread()->quit();
    processor->thread()->wait();

         注意在构造函数中没有分配任何父函数,并且还确保将其定义为指针,有父对象的对象不能移动到新线程中。

8.3 线程同步工具 

         多线程往往要解决线程间的冲突以及因为并行而产生的问题。解决这些问题的类被称为线程同步工具。

8.3.1 互斥锁

forever{

        image = imread"image.jpg";

}

        forever宏可以用于创建无限循环。

        然后另一个线程一直在处理这个图像

forever{

        cvtColor(image, image, CV_BGR2GRAY);

        resize(image, image, Size(), 0.5, 0.5);

}

        如果两个线程同时运行,就有可能在,某一时刻调用图片冲突,因此加入锁来解决,确保线程同时只有一个线程在访问该对象

forever{

        imageMutex.lock();

        image = imread"image.jpg";

        imageMutex.unlock();

}

forever{

        imageMutex.lock();

        cvtColor(image, image, CV_BGR2GRAY);

        resize(image, image, Size(), 0.5, 0.5);

        imageMutex.unlock();

}

 最好用QMutexLocker类来重写锁

 

forever{

        QMutexLocker locker(&imageMutex);

        image = imread"image.jpg";

}

forever{

        QMutexLocker locker(&imageMutex);

        cvtColor(image, image, CV_BGR2GRAY);

        resize(image, image, Size(), 0.5, 0.5);

}

 8.3.2 读写锁

        假设希望不同的线程能够同时读取对象(例如变量、类实例、文件等);但是希望保证只有一个线程可以在任何给的给定的时间修改(或者写入)该对象。Qt提供了QReadWriteLock类,像QMutex类一样使用,区别在于它提供了一个用与读取的锁函数(lockForRead)和另一个用于写入的锁函数(lockForWrite)。特性如下:

        如果线程中的调用了lockForRead函数,其他线程仍然可以调用lockForRead并为了读取而访问敏感对象(指的是正在使用锁的对象)。

        此外,如果在线程中带哦用lockForRead函数,则任何调用lockForWrite的线程都将被阻塞,直到该线程调用解锁(unlock)为止。

        如果在线程中调用lockForWrite函数,则所有其他线程都将被阻塞,直到解锁

        如果在线程中调用lockForWrite函数,而前一个线程有一个读取锁,那么所有调用lockForRead的新线程都必须等待需要写入锁得线程,因此需要lockForWrite的线程都将被赋予更高级的优先级。

8.3.3 信号量

        信号量类似增强的互斥锁,不仅能完成锁定和解锁操作,而且还可以跟踪可用资源数量,Qt提供了一个名为Qsemaphore类,可用函数如下:

        acquire:可以获得特定数量的所需资源

        release:可以用来释放已经使用并且不在需要的特定数量的资源

        available:可以用来获取可用资源的数量

//创建100兆字节的可用内存范围

QSemaphore memSem(100);

 //在每个线程中,获取并释放内存

memSem.acquire(X);

process_image();

memSem.release(X);

8.3.4 等待条件 

        Qt框架有一个名为QWaitCondition类,可以让线程在满足一些其他条件之后,才继续进行,例如两个线程,一个创造图像,一个修改图像,如果图像未被创造出来,那么即时轮到该线程也无法进行后续步骤。

 forever{

        mutex.lock();

        imageExistsCond.wait(&mutex);

        read_image();

        mutex.unlock();

}

//另一个线程

forever{

        if(QFile::exits("image.jpg")){

        iamgeExistsCond.wakeAll();   //唤醒

        }

}

8.4基于QtConcurrent的高级多线程

        Qt还提供高级API,用于在不需要处理线程同步工具的情况下创建多线程程序。下面的函数通常使用高级QtConcurrent API,用来处理多线程:

        filter:用于滤波列表,提供含滤波数据的列表和一个滤波函数

        filtered:与filter的工作方式类似,区别是返回filtered滤波后的列表,而不是更新输入列表

        filteredReduced:与filtered相似,但是filteredReduced还应用第二个函数将每一项传给滤波器

        map:可用于将一个特定的函数应用到一个列表的所有项

        mapped:与map的工作方式类似,区别是返回mapped结果列表,而不是更新输入列表

        mappedReduced:与mapped相似,但是mappedReduced还将第二个函数应用到mapped函数之后的每一项

        run:在一个单独线程中轻松执行这个函数

ConcurrentCV程序的总结:

        QFutureWatcher类是监控的QtConcurrent计算的一种便捷方法,并将之分配给一个Qfuture类,在这种情况下QfutureWatcher被定义为指针,并且在完成进程之后将其删除,原因是QFutureWatcher必须在进程继续的过程中保持激活状态,并且只有完成计算之后才能删除。因此,首先建立QFutureWatcher所需的所有连接,然后,设置相应的future变量,在建立连接之后,确保设定了future是很重要的。

        QFuture包含以下用于控制计算的函数:

        pause、resume、cancel

        以下函数检索计算状态:

        isStarted、isPaused、isRunning、isFinished、isCanceled

使用以下函数设置QtConcurrent函数的最大线程数:

QThreadPool::globalInstance()->setMaxThreadCount(n);

 也可以定义筛选函数

bool filterImage(QFileInfo &info){

        if(info.created().date.year()<2015)

                true;

        else

                false;

}

//调用

QtConcurrent::filter(list,filterImage);

//或者

QtConcurrent::filteredReduced(list,filterImage,addDateTime);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值