C++線程安全的隊列你了解嘛
更新時間:2022年03月10日 10:31:46 作者:吃米飯
這篇文章主要為大家詳細介紹了C++線程安全的隊列,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

無界隊列
#include<queue>
#include<mutex>
#include<condition_variable>
#include<optional>
#include<cassert>
#include<thread>
template<typename T,typename Container = std::queue<T>>
class Queue //無界隊列
{
public:
Queue() = default;
~Queue() = default;
//禁止拷貝和移動,編譯器會自動delete
/*Queue(const Queue&) = delete;
Queue(Queue&&) = delete;
Queue& operator=(const Queue&) = delete;
Queue& operator=(Queue&&) = delete;*/
void push(const T& val)
{
emplace(val);
}
void push(T&& val)
{
emplace(std::move(val));
}
template<typename...Args>
void emplace(Args&&...args)
{
std::lock_guard lk{ mtx_ };
q_.push(std::forward<Args>(args)...);
cv_.notify_one();
}
T pop()//阻塞
{
std::unique_lock lk{ mtx_ };
cv_.wait(lk, [this] {return !q_.empty(); });//如果隊列不為空就繼續(xù)執(zhí)行,否則阻塞
assert(!q_.empty());
T ret{ std::move_if_noexcept(q_.front()) };
q_.pop();
return ret;
}
std::optional<T> try_pop()//非阻塞
{
std::unique_lock lk{ mtx_ };
if (q_.empty())return {};
std::optional<T> ret{ std::move_if_noexcept(q_.front()) };
q_.pop();
return ret;
}
bool empty()const
{
std::lock_guard lk{ mtx_ };
return q_.empty();
}
private:
Container q_;
mutable std::mutex mtx_;
std::condition_variable cv_;
};
#include<iostream>
int main()
{
Queue<int>q;
std::thread t1(
[&] {
for (int i = 0; i < 100; ++i)
{
q.push(i);
}
});
std::thread t2(
[&] {
for (int i = 0; i < 100; ++i)
{
//std::cout<<q.pop()<<" ";
if (auto ret = q.try_pop())
{
std::cout << *ret<<" ";
}
}
});
t1.join();
t2.join();
return 0;
}
有界隊列
#include<mutex>
#include<condition_variable>
#include<boost/circular_buffer.hpp>
#include<optional>
template<typename T>
class Queue
{
public:
Queue(size_t capacity) :q_{ capacity }{}
template<typename T>
void push(T&& val)//阻塞
{
std::unique_lock lk{ mtx_ };
not_full_.wait(lk, [this] {return !q_.full(); });
assert(!q_.full());
q_.push_back(std::move(std::forward<T>(val)));
not_empty_.notify_one();
}
template<typename T>
bool try_push(T&& val)//非阻塞
{
std::lock_guard lk{ mtx_ };
if (q_.full())return false;
q_.push_back(std::forward<T>(val));
not_empty_.notify_one();
return true;
}
T pop()//阻塞
{
std::unique_lock lk{ mtx_ };
not_empty_.wait(lk, [this] {return !q_.empty(); });
asert(!q_.empty());
T ret{ std::move_if_noexcept(q_.front()) };
q_.pop_front();
not_full_.notify_one();
return ret;
}
std::optional<T> try_pop()//非阻塞
{
std::lock_guard lk{ mtx_ };
if (q_.empty())return {};
std::optional<T> ret{ std::move_if_noexcept(q_.front()) };
q_.pop_front();
not_full_.notify_one();
return ret;
}
private:
boost::circular_buffer<T>q_;
std::mutex mtx_;
std::condition_variable not_full_;
std::condition_variable not_empty_;
};
#include<iostream>
int main()
{
Queue<int>q(10);
std::thread t1(
[&] {
for (int i = 0; i < 100; ++i)
{
q.push(i);
}
});
std::thread t2(
[&] {
for (int i = 0; i < 100; ++i)
{
//std::cout<<q.pop()<<" ";
if (auto ret = q.try_pop())
{
std::cout << *ret << " ";
}
}
});
t1.join();
t2.join();
return 0;
}
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
C++示例分析內聯(lián)函數與引用變量及函數重載的使用
為了消除函數調用的時空開銷,C++ 提供一種提高效率的方法,即在編譯時將函數調用處用函數體替換,類似于C語言中的宏展開。這種在函數調用處直接嵌入函數體的函數稱為內聯(lián)函數(Inline Function),又稱內嵌函數或者內置函數2022-08-08

