Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 使用条件变量在线程之间通信_Multithreading_Opencv_C++11 - Fatal编程技术网

Multithreading 使用条件变量在线程之间通信

Multithreading 使用条件变量在线程之间通信,multithreading,opencv,c++11,Multithreading,Opencv,C++11,我正在尝试使用多线程实现一种处理直方图图像的算法 最常见的方法之一是拆分多个线程,在每个线程上创建一个缓存缓冲区,在缓存缓冲区上做直方图,然后锁定一个互斥锁,将本地上的值添加到输出向量,然后解锁缓冲区 这种方法非常有效,但会造成“堵塞”。 我的意思是数据的添加不能同时实现 在大多数情况下,当值的范围很短(例如0-255)时,进行加法所需的时间非常快,可以忽略不计 如果数据范围更大,例如在热图像上,这一次可能会变得更重要。 热图像通常是无符号短矩阵,即使值不使用完整范围(0-65535),算法也必

我正在尝试使用多线程实现一种处理直方图图像的算法

最常见的方法之一是拆分多个线程,在每个线程上创建一个缓存缓冲区,在缓存缓冲区上做直方图,然后锁定一个互斥锁,将本地上的值添加到输出向量,然后解锁缓冲区

这种方法非常有效,但会造成“堵塞”。 我的意思是数据的添加不能同时实现

在大多数情况下,当值的范围很短(例如0-255)时,进行加法所需的时间非常快,可以忽略不计

如果数据范围更大,例如在热图像上,这一次可能会变得更重要。 热图像通常是无符号短矩阵,即使值不使用完整范围(0-65535),算法也必须处理所有范围

为了加快一点处理速度,我想启动一个后台线程来进行添加,而“前台”线程只将数据写入预分配的缓冲区

因此,“前台”线程的工作基本上是:

  • 从循环缓冲区获取缓冲区

  • 处理指定数据集的直方图(例如,从第n行到第m行)

-通知后台缓冲区操作已完成

用于执行以下操作的后台线程:

  • 等待通知到达,检查可用缓冲区的数量是否低于缓冲区的数量

  • 如果条件为真,则从可用的缓冲区中查找要处理的缓冲区

  • 使用输出缓冲区进行加法

  • 使处理后的缓冲区可重用

我不太熟悉条件变量。 因此,为了使用条件变量检查线程之间的通信,我编写了以下玩具示例:

玩具

我必须检查变量“it”的位置,否则它可能位于缓冲区大小之外

我的想法是: -在前台线程的末尾,将向后台线程发送通知。 -然后后台线程处理缓冲区(或缓冲区,具体取决于线程结束的速度)。 -最后,后台线程通知下一个前台线程(在方法get_buffer()中),它已完成对缓冲区的处理,并使其可重用

当后台线程正在寻找一个线程时,请遵循以下语句,它将使用该线程在Buf_start和Buf_end之间找到它

因此,在方法背景中查找缓冲区的方法为:

while(!it->_is_available )
    it++;
经过几个小时的测试,我不知道出了什么问题。 我还想知道这个算法是否真的像我想的那样有效? 线程之间是否有更高效、更少处理的通信方式

提前谢谢。

我修好了!:)

我从“玩具”一类中找出了几个问题

操作符()
的重载中,我复制方法
get buffer()
的代码。 我围绕等待条件执行了一个阻塞函数,以避免在线程上按顺序执行。 条件变量所需的
unique\u lock
仅存在于block函数的方括号之间,如在已评估等待条件时,互斥锁
\u mtx\u前台
处于解锁状态

然后,为了防止在搜索可用缓冲区期间出站,已将
while
循环替换为
for
循环。 问题在于满足指针增量的条件

在“背景”线程上,我添加了一个循环。 其想法是:

  • 后台线程必须一直运行到 算法
  • 后台线程正在等待通知 从一个前台线程
  • 寻找要处理的缓冲区, 处理它,使其可用,并将其通知前台 线
  • 重做,直到处理完所有缓冲区,然后返回 2)
  • 这里的一些部分已经被“深度”修改

    名为toy2的
    类玩具的最新实现如下:

    #ifndef TOY
    #define TOY
    
    
    #include <opencv2/core.hpp>
    #include <opencv2/core/utility.hpp>
    
    #include <iostream>
    #include <iterator>
    
    #include <thread>
    #include <mutex>
    #include <atomic>
    #include <condition_variable>
    
    namespace toy
    {
    
    class toy2 : public cv::ParallelLoopBody
    {
    
    private:
    
        struct elem_t
        {
            int _id;
            std::atomic_bool _is_available;
            std::atomic_bool _is_inprocess;
    
            inline elem_t():
                _id(-1),
                _is_available(true),
                _is_inprocess(false)
            {}
    
            // needed for the memory reservation because atomic_bool copy constructor is deleted.
            inline elem_t(const elem_t& obj):
                _id(obj._id),
                _is_available((bool)obj._is_available),
                _is_inprocess((bool)obj._is_inprocess)
            {}
    
            // needed for the memory reservation because atomic_bool copy constructor is deleted.
            inline elem_t(elem_t&& obj):
                _id(obj._id),
                _is_available((bool)obj._is_available),
                _is_inprocess((bool)obj._is_inprocess)
            {}
    
            // help for the initialization using iota.
            inline elem_t& operator=(const int& id)
            {
                this->_id = id;
    
                return (*this);
            }
        };
    
        mutable std::vector<elem_t> _buffer;
        std::vector<elem_t*> _elements;
    
        std::atomic_bool _run;
    
        mutable std::atomic_size_t _nb_available_buffers;
    
        mutable std::mutex _mtx_thread;
        mutable std::mutex _mtx_foreground;
        mutable std::mutex _mtx_background;
    
        mutable std::condition_variable _cv_ctor_dtor;
        mutable std::condition_variable _cv_foreground;
        mutable std::condition_variable _cv_background;
    
    
    
        void background()
        {
            std::cout<<"background has been detach"<<std::endl;
    
    
            while(this->_run)
            {
                {
                std::unique_lock<std::mutex> lck(this->_mtx_background);
    
                this->_cv_background.wait(lck);
                }
    
                // Condition for stoping terminate the thread.
                if(!this->_run)
                    break;
    
                while(true)
                {
    
                    typename std::vector<elem_t>::iterator it = std::find_if(this->_buffer.begin(),this->_buffer.end(),[](const elem_t& v){ return (!v._is_available && !v._is_inprocess);});
    
                    if(it == this->_buffer.end())
                        break;
    
                    std::cout<<"the background is making the element : "<<it->_id<<" available."<<std::endl;
    
                    it->_is_available = true;
                    it->_is_inprocess = false;
    
                    this->_nb_available_buffers++;
    
                    this->_cv_foreground.notify_one();
                }
    
    
            }
        }
    
    public:
    
    
        toy2():
            _buffer(),
            _elements(),
            _run(false),
            _nb_available_buffers(0),
            _mtx_thread(),
            _mtx_foreground(),
            _mtx_background(),
            _cv_ctor_dtor(),
            _cv_foreground(),
            _cv_background()
        {
            const int nb_threads = cv::getNumThreads();
    
            this->_nb_available_buffers = nb_threads;
    
            this->_buffer.reserve(nb_threads);
            this->_buffer.resize(this->_buffer.capacity());
    
            this->_elements.reserve(this->_buffer.size());
            this->_elements.resize(this->_buffer.size(),nullptr);
    
    
    
            std::iota(this->_buffer.begin(),this->_buffer.end(),0);
    
            for(int i=0;i<this->_buffer.size();i++)
                this->_elements[i] = std::addressof(this->_buffer[i]);
    
            std::thread th([this]
            {
                // Notify to the constructor.
                this->_cv_ctor_dtor.notify_one();
    
                this->background();
    
                // Notify to the destructor.
                this->_cv_ctor_dtor.notify_one();
            });
    
            this->_run = true;
    
            std::unique_lock<std::mutex> lck(this->_mtx_thread);
    
            th.detach();
    
            this->_cv_ctor_dtor.wait(lck);
    
        }
    
    
        ~toy2()
        {
            this->_run = false;
            this->_cv_background.notify_one();
    
            std::unique_lock<std::mutex> lck(this->_mtx_thread);
    
            this->_cv_ctor_dtor.wait(lck);
        }
    
        void operator()(const cv::Range& range)const
        {
            {
                std::unique_lock<std::mutex> lck(this->_mtx_foreground);
    
                this->_cv_foreground.wait(lck,[&]{return this->_nb_available_buffers>0;});
            }
    
            typename std::vector<elem_t>::iterator it = std::find_if(this->_buffer.begin(),this->_buffer.end(),[](const elem_t& v){return (bool)v._is_available;});
    
    //        for(it = this->_buffer.begin();it != this->_buffer.end();it++)
    //            if(it->_is_available)
    //                break;
    
    
    
            it->_is_available = false;
            it->_is_inprocess = true;
    
            this->_nb_available_buffers--;
    
            std::cout<<"the foreground is processing the element : "<<it->_id<<" "<<std::this_thread::get_id()<<std::endl;
    
    
    
    
            std::this_thread::sleep_for(std::chrono::milliseconds(2));
    //        std::this_thread::sleep_for(std::chrono::seconds(2));
    
            it->_is_inprocess = false;
    
            this->_cv_background.notify_one();
    
            std::cout<<"end thread"<<std::endl;
        }
    
    };
    
        }
    #endif
    
    \ifndef玩具
    #定义玩具
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    名称空间玩具
    {
    类toy2:公共cv::ParallelLoopBody
    {
    私人:
    结构元素
    {
    内部id;
    std::原子布尔可用;
    std::原子布尔在进程中;
    内联元素()
    _id(-1),
    __是否可用(正确),
    _正在处理中(错误)
    {}
    //由于已删除原子复制构造函数,因此需要内存保留。
    内联元件(常量元件和对象):
    _id(对象id),
    _是否可用((bool)obj.\u是否可用),
    _正在处理((bool)obj.\u正在处理)
    {}
    //由于已删除原子复制构造函数,因此需要内存保留。
    内联元素(元素和对象):
    _id(对象id),
    _是否可用((bool)obj.\u是否可用),
    _正在处理((bool)obj.\u正在处理)
    {}
    //使用iota进行初始化的帮助。
    内联元素与运算符=(常量int&id)
    {
    这个->\u id=id;
    返回(*本条);
    }
    };
    可变std::vector\u缓冲区;
    std::矢量元素;
    标准:原子运行;
    可变标准::原子大小\u t\u nb\u可用\u缓冲区;
    可变std::互斥线程;
    可变std::互斥体_mtx_前景;
    可变std::互斥体mtx_background;
    可变标准::条件变量变量变量变量;
    可变标准::条件变量前景;
    可变标准::条件变量背景;
    无效背景()
    {
    标准::cout_运行)
    打破
    while(true)
    {
    
        // Method by spining.
        // While the available buffer is not find I am looking for it.
        // When I'll find I may have done multiple pass.
        while(it->_is_available || it->_is_inprocess)
        {
            it++;
    
            if(it == this->buf_end)
                it = this->buf_begin;
        }
    
    while(!it->_is_available )
        it++;
    
    #ifndef TOY
    #define TOY
    
    
    #include <opencv2/core.hpp>
    #include <opencv2/core/utility.hpp>
    
    #include <iostream>
    #include <iterator>
    
    #include <thread>
    #include <mutex>
    #include <atomic>
    #include <condition_variable>
    
    namespace toy
    {
    
    class toy2 : public cv::ParallelLoopBody
    {
    
    private:
    
        struct elem_t
        {
            int _id;
            std::atomic_bool _is_available;
            std::atomic_bool _is_inprocess;
    
            inline elem_t():
                _id(-1),
                _is_available(true),
                _is_inprocess(false)
            {}
    
            // needed for the memory reservation because atomic_bool copy constructor is deleted.
            inline elem_t(const elem_t& obj):
                _id(obj._id),
                _is_available((bool)obj._is_available),
                _is_inprocess((bool)obj._is_inprocess)
            {}
    
            // needed for the memory reservation because atomic_bool copy constructor is deleted.
            inline elem_t(elem_t&& obj):
                _id(obj._id),
                _is_available((bool)obj._is_available),
                _is_inprocess((bool)obj._is_inprocess)
            {}
    
            // help for the initialization using iota.
            inline elem_t& operator=(const int& id)
            {
                this->_id = id;
    
                return (*this);
            }
        };
    
        mutable std::vector<elem_t> _buffer;
        std::vector<elem_t*> _elements;
    
        std::atomic_bool _run;
    
        mutable std::atomic_size_t _nb_available_buffers;
    
        mutable std::mutex _mtx_thread;
        mutable std::mutex _mtx_foreground;
        mutable std::mutex _mtx_background;
    
        mutable std::condition_variable _cv_ctor_dtor;
        mutable std::condition_variable _cv_foreground;
        mutable std::condition_variable _cv_background;
    
    
    
        void background()
        {
            std::cout<<"background has been detach"<<std::endl;
    
    
            while(this->_run)
            {
                {
                std::unique_lock<std::mutex> lck(this->_mtx_background);
    
                this->_cv_background.wait(lck);
                }
    
                // Condition for stoping terminate the thread.
                if(!this->_run)
                    break;
    
                while(true)
                {
    
                    typename std::vector<elem_t>::iterator it = std::find_if(this->_buffer.begin(),this->_buffer.end(),[](const elem_t& v){ return (!v._is_available && !v._is_inprocess);});
    
                    if(it == this->_buffer.end())
                        break;
    
                    std::cout<<"the background is making the element : "<<it->_id<<" available."<<std::endl;
    
                    it->_is_available = true;
                    it->_is_inprocess = false;
    
                    this->_nb_available_buffers++;
    
                    this->_cv_foreground.notify_one();
                }
    
    
            }
        }
    
    public:
    
    
        toy2():
            _buffer(),
            _elements(),
            _run(false),
            _nb_available_buffers(0),
            _mtx_thread(),
            _mtx_foreground(),
            _mtx_background(),
            _cv_ctor_dtor(),
            _cv_foreground(),
            _cv_background()
        {
            const int nb_threads = cv::getNumThreads();
    
            this->_nb_available_buffers = nb_threads;
    
            this->_buffer.reserve(nb_threads);
            this->_buffer.resize(this->_buffer.capacity());
    
            this->_elements.reserve(this->_buffer.size());
            this->_elements.resize(this->_buffer.size(),nullptr);
    
    
    
            std::iota(this->_buffer.begin(),this->_buffer.end(),0);
    
            for(int i=0;i<this->_buffer.size();i++)
                this->_elements[i] = std::addressof(this->_buffer[i]);
    
            std::thread th([this]
            {
                // Notify to the constructor.
                this->_cv_ctor_dtor.notify_one();
    
                this->background();
    
                // Notify to the destructor.
                this->_cv_ctor_dtor.notify_one();
            });
    
            this->_run = true;
    
            std::unique_lock<std::mutex> lck(this->_mtx_thread);
    
            th.detach();
    
            this->_cv_ctor_dtor.wait(lck);
    
        }
    
    
        ~toy2()
        {
            this->_run = false;
            this->_cv_background.notify_one();
    
            std::unique_lock<std::mutex> lck(this->_mtx_thread);
    
            this->_cv_ctor_dtor.wait(lck);
        }
    
        void operator()(const cv::Range& range)const
        {
            {
                std::unique_lock<std::mutex> lck(this->_mtx_foreground);
    
                this->_cv_foreground.wait(lck,[&]{return this->_nb_available_buffers>0;});
            }
    
            typename std::vector<elem_t>::iterator it = std::find_if(this->_buffer.begin(),this->_buffer.end(),[](const elem_t& v){return (bool)v._is_available;});
    
    //        for(it = this->_buffer.begin();it != this->_buffer.end();it++)
    //            if(it->_is_available)
    //                break;
    
    
    
            it->_is_available = false;
            it->_is_inprocess = true;
    
            this->_nb_available_buffers--;
    
            std::cout<<"the foreground is processing the element : "<<it->_id<<" "<<std::this_thread::get_id()<<std::endl;
    
    
    
    
            std::this_thread::sleep_for(std::chrono::milliseconds(2));
    //        std::this_thread::sleep_for(std::chrono::seconds(2));
    
            it->_is_inprocess = false;
    
            this->_cv_background.notify_one();
    
            std::cout<<"end thread"<<std::endl;
        }
    
    };
    
        }
    #endif