C++多线程,多线程通信,队列

1,使用


TQueueConcurrent<std::vector<std::string>> fifo_queue;

...
...

fifo_queue.emplace_back(string_ret);
LOG(INFO) << "fifo_queue size: " << fifo_queue.size();
...
...

if(!fifo_queue.is_empty()) {
	std::vector<std::string> string_ret = fifo_queue.pop_front_not_wait();
	...
	...
	}
}

2,实现

template< typename T >
class TQueueConcurrent {
    using const_iterator = typename std::deque<T>::const_iterator;
 
public:
    //! \brief Emplaces a new instance of T in front of the deque
    template<typename... Args>
    void emplace_front( Args&&... args )
    {
        addData_protected( [&] {
            _collection.emplace_front(std::forward<Args>(args)...);
        } );
    }
 
    //! \brief Emplaces a new instance of T at the back of the deque
    template<typename... Args>
    void emplace_back( Args&&... args )
    {
        addData_protected( [&] {
            _collection.emplace_back(std::forward<Args>(args)...);
        } );
    }
 
    //! \brief Returns the front element and removes it from the collection
    //!
    //!        No exception is ever returned as we garanty that the deque 
    //is not empty
    //!        before trying to return data.
    T pop_front( void ) noexcept
    {
        std::unique_lock<std::mutex> lock{_mutex};
        while (_collection.empty()) {
            _condNewData.wait(lock);
        }
        auto elem = std::move(_collection.front());
        _collection.pop_front();
        return elem;
    }
    T pop_front_not_wait( void ) noexcept
    {
        std::unique_lock<std::mutex> lock{_mutex};
        auto elem = std::move(_collection.front());
        _collection.pop_front();
        lock.unlock();
        return elem;
    }
    bool is_empty() {
        std::unique_lock<std::mutex> lock{_mutex};
        bool is_empty = _collection.empty();
        lock.unlock();
        return is_empty;
    }
    int size(){
        std::unique_lock<std::mutex> lock{_mutex};
        int size = _collection.size();
        lock.unlock();
        return size;
    }
 
private:
 
    //! \brief Protects the deque, calls the provided function and 
    //notifies the presence of new data
    //! \param The concrete operation to be used. It MUST be an operation 
    //which will add data to the deque,
    //!        as it will notify that new data are available!
    template<class F>
    void addData_protected(F&& fct)
    {
        std::unique_lock<std::mutex> lock{ _mutex };
        fct();
        lock.unlock();
        _condNewData.notify_one();
    }
 
    std::deque<T> _collection;  ///< Concrete, not thread safe, storage.
    std::mutex   _mutex;        ///< Mutex protecting the concrete storage
    std::condition_variable _condNewData;   ///< Condition used to notify 
                                            ///that new data are available.
};

3,知识点

1, std::mutex

https://blog.csdn.net/u012507022/article/details/85909567

std::mutex是C++11中最基本的互斥量,std::mutex对象提供了独占所有权的特性,不支持递归地对std::mutex对象上锁。

    std::mutex成员函数:

    (1)、构造函数:std::mutex不支持copy和move操作,最初的std::mutex对象是处于unlocked状态。

    (2)、lock函数:互斥锁被锁定。线程申请该互斥锁,如果未能获得该互斥锁,则调用线程将阻塞(block)在该互斥锁上;如果成功获得该互诉锁,该线程一直拥有该互斥锁直到调用unlock解锁;如果该互斥锁已经被当前调用线程锁住,则产生死锁(deadlock)。

    (3)、unlock函数:解锁,释放调用线程对该互斥锁的所有权。

    (4)、try_lock:尝试锁定互斥锁。如果互斥锁被其他线程占有,则当前调用线程也不会被阻塞,而是由该函数调用返回false;如果该互斥锁已经被当前调用线程锁住,则会产生死锁。其中std::mutex就是lock、unlock。std::lock_guard与std::mutex配合使用,把锁放到lock_guard中时,mutex自动上锁,lock_guard析构时,同时把mutex解锁。
     (5)、native_handle:返回当前句柄。

2,std::condition_variable

https://blog.csdn.net/fengbingchun/article/details/73695596

条件变量std::condition_variable用于多线程之间的通信,它可以阻塞一个或同时阻塞多个线程。std::condition_variable需要与std::unique_lock配合使用。std::condition_variable效果上相当于包装了pthread库中的pthread_cond_*()系列的函数。

当std::condition_variable对象的某个wait函数被调用的时候,它使用std::unique_lock(通过std::mutex)来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的std::condition_variable对象上调用了notification函数来唤醒当前线程。

std::condition_variable对象通常使用std::unique_lock<std::mutex>来等待,如果需要使用另外的lockable类型,可以使用std::condition_variable_any类。

std::condition_variable类的成员函数:

(1)、构造函数:仅支持默认构造函数,拷贝、赋值和移动(move)均是被禁用的。

(2)、wait:当前线程调用wait()后将被阻塞,直到另外某个线程调用notify_*唤醒当前线程;当线程被阻塞时,该函数会自动调用std::mutex的unlock()释放锁,使得其它被阻塞在锁竞争上的线程得以继续执行。一旦当前线程获得通知(notify,通常是另外某个线程调用notify_*唤醒了当前线程),wait()函数也是自动调用std::mutex的lock()。wait分为无条件被阻塞和带条件的被阻塞两种。

无条件被阻塞:调用该函数前,当前线程应该已经对unique_lock<mutex> lck完成了加锁。所有使用同一个条件变量的线程必须在wait函数中使用同一个unique_lock<mutex>。该wait函数内部会自动调用lck.unlock()对互斥锁解锁,使得其他被阻塞在互斥锁上的线程恢复执行。使用本函数被阻塞的当前线程在获得通知(notified,通过别的线程调用 notify_*系列的函数)而被唤醒后,wait()函数恢复执行并自动调用lck.lock()对互斥锁加锁。

带条件的被阻塞:wait函数设置了谓词(Predicate),只有当pred条件为false时调用该wait函数才会阻塞当前线程,并且在收到其它线程的通知后只有当pred为true时才会被解除阻塞。因此,等效于while (!pred())  wait(lck).

(3)、wait_for:与wait()类似,只是wait_for可以指定一个时间段,在当前线程收到通知或者指定的时间超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其它线程的通知,wait_for返回,剩下的步骤和wait类似。

(4)、wait_until:与wait_for类似,只是wait_until可以指定一个时间点,在当前线程收到通知或者指定的时间点超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其它线程的通知,wait_until返回,剩下的处理步骤和wait类似。

(5)、notify_all: 唤醒所有的wait线程,如果当前没有等待线程,则该函数什么也不做。

(6)、notify_one:唤醒某个wait线程,如果当前没有等待线程,则该函数什么也不做;如果同时存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值