将互斥保护构建到C++;上课? 我正在尝试为我正在进行的项目在C++中实现一个生产者/消费者模型多线程程序。其基本思想是,主线程创建第二个线程来监视串行端口中的新数据,处理数据,并将结果放入由主线程定期轮询的缓冲区中。我以前从未编写过多线程程序。我已经阅读了很多教程,但都是C语言的。我想我已经掌握了基本概念,但我正在尝试用C++来实现它。对于缓冲区,我想创建一个内置互斥保护的数据类。这就是我想到的
1) 我走错方向了吗?有没有更智能的方法来实现受保护的数据类 2) 如果两个线程试图同时调用将互斥保护构建到C++;上课? 我正在尝试为我正在进行的项目在C++中实现一个生产者/消费者模型多线程程序。其基本思想是,主线程创建第二个线程来监视串行端口中的新数据,处理数据,并将结果放入由主线程定期轮询的缓冲区中。我以前从未编写过多线程程序。我已经阅读了很多教程,但都是C语言的。我想我已经掌握了基本概念,但我正在尝试用C++来实现它。对于缓冲区,我想创建一个内置互斥保护的数据类。这就是我想到的,c++,multithreading,mutex,C++,Multithreading,Mutex,1) 我走错方向了吗?有没有更智能的方法来实现受保护的数据类 2) 如果两个线程试图同时调用ProtectedBuffer::add_back(),那么下面的代码会发生什么情况 #include <deque> #include "pthread.h" template <class T> class ProtectedBuffer { std::deque<T> buffer; pthread_mutex_t mutex; public: vo
ProtectedBuffer::add_back()
,那么下面的代码会发生什么情况
#include <deque>
#include "pthread.h"
template <class T>
class ProtectedBuffer {
std::deque<T> buffer;
pthread_mutex_t mutex;
public:
void add_back(T data) {
pthread_mutex_lock(&mutex);
buffer.push_back(data);
pthread_mutex_unlock(&mutex);
}
void get_front(T &data) {
pthread_mutex_lock(&mutex);
data = buffer.front();
buffer.pop_front();
pthread_mutex_unlock(&mutex);
}
};
#包括
#包括“pthread.h”
模板
类ProtectedBuffer{
std::deque缓冲区;
pthread_mutex_t mutex;
公众:
void add_back(T数据){
pthread_mutex_lock(&mutex);
缓冲区。推回(数据);
pthread_mutex_unlock(&mutex);
}
无效获取前端(T和数据){
pthread_mutex_lock(&mutex);
data=buffer.front();
buffer.pop_front();
pthread_mutex_unlock(&mutex);
}
};
编辑:
谢谢你的建议。我已经尝试在下面实现它们。我还添加了一些错误检查,因此如果一个线程设法锁定同一个互斥锁两次,它将失败。我想
#include "pthread.h"
#include <deque>
class Lock {
pthread_mutex_t &m;
bool locked;
int error;
public:
explicit Lock(pthread_mutex_t & _m) : m(_m) {
error = pthread_mutex_lock(&m);
if (error == 0) {
locked = true;
} else {
locked = false;
}
}
~Lock() {
if (locked)
pthread_mutex_unlock(&m);
}
bool is_locked() {
return locked;
}
};
class TryToLock {
pthread_mutex_t &m;
bool locked;
int error;
public:
explicit TryToLock(pthread_mutex_t & _m) : m(_m) {
error = pthread_mutex_trylock(&m);
if (error == 0) {
locked = true;
} else {
locked = false;
}
}
~TryToLock() {
if (locked)
pthread_mutex_unlock(&m);
}
bool is_locked() {
return locked;
}
};
template <class T>
class ProtectedBuffer{
pthread_mutex_t mutex;
pthread_mutexattr_t mattr;
std::deque<T> buffer;
bool failbit;
ProtectedBuffer(const ProtectedBuffer& x);
ProtectedBuffer& operator= (const ProtectedBuffer& x);
public:
ProtectedBuffer() {
pthread_mutexattr_init(&mattr);
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&mutex, &mattr);
failbit = false;
}
~ProtectedBuffer() {
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&mattr);
}
void add_back(T &data) {
Lock lck(mutex);
if (!lck.locked()) {
failbit = true;
return;
}
buffer.push_back(data);
failbit = false;
}
void get_front(T &data) {
Lock lck(mutex);
if (!lck.locked()) {
failbit = true;
return;
}
if (buffer.empty()) {
failbit = true;
return;
}
data = buffer.front();
buffer.pop_front();
failbit = false;
}
void try_get_front(T &data) {
TryToLock lck(mutex);
if (!lck.locked()) {
failbit = true;
return;
}
if (buffer.empty()) {
failbit = true;
return;
}
data = buffer.front();
buffer.pop_front();
failbit = false;
}
void try_add_back(T &data) {
TryToLock lck(mutex);
if (!lck.locked()) {
failbit = true;
return;
}
buffer.push_back(data);
failbit = false;
}
};
#包括“pthread.h”
#包括
类锁{
pthread_mutex_t&m;
布尔锁定;
整数误差;
公众:
显式锁(pthread\u mutex\u t&\u m):m(\u m){
错误=pthread\u mutex\u lock(&m);
如果(错误==0){
锁定=真;
}否则{
锁定=错误;
}
}
~Lock(){
如果(已锁定)
pthread_mutex_unlock(&m);
}
布尔已锁定(){
返回锁定;
}
};
类TryToLock{
pthread_mutex_t&m;
布尔锁定;
整数误差;
公众:
显式TryToLock(pthread\u mutex\u t&\u m):m(\u m){
错误=pthread\u mutex\u trylock(&m);
如果(错误==0){
锁定=真;
}否则{
锁定=错误;
}
}
~TryToLock(){
如果(已锁定)
pthread_mutex_unlock(&m);
}
布尔已锁定(){
返回锁定;
}
};
模板
类ProtectedBuffer{
pthread_mutex_t mutex;
pthread_mutextatr_t mattr;
std::deque缓冲区;
布尔故障位;
ProtectedBuffer(常量ProtectedBuffer&x);
ProtectedBuffer和运算符=(const ProtectedBuffer和x);
公众:
ProtectedBuffer(){
pthread_mutexattr_init(&mattr);
pthread_mutextatr_settype(&mattr,pthread_MUTEX_ERRORCHECK);
pthread_mutex_init(&mutex,&mattr);
failbit=false;
}
~ProtectedBuffer(){
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&mattr);
}
无效添加回(T&data){
锁定lck(互斥);
如果(!lck.locked()){
failbit=true;
返回;
}
缓冲区。推回(数据);
failbit=false;
}
无效获取前端(T和数据){
锁定lck(互斥);
如果(!lck.locked()){
failbit=true;
返回;
}
if(buffer.empty()){
failbit=true;
返回;
}
data=buffer.front();
buffer.pop_front();
failbit=false;
}
无效尝试获取前端(T&data){
TryToLock lck(互斥锁);
如果(!lck.locked()){
failbit=true;
返回;
}
if(buffer.empty()){
failbit=true;
返回;
}
data=buffer.front();
buffer.pop_front();
failbit=false;
}
无效尝试添加回(T&data){
TryToLock lck(互斥锁);
如果(!lck.locked()){
failbit=true;
返回;
}
缓冲区。推回(数据);
failbit=false;
}
};
有几件事:
- 您需要在构造函数中初始化
,并在析构函数中用mutex
pthread\u mutex\u destroy释放它
- 您必须使类不可复制和不可赋值(或者正确地实现复制构造函数和赋值运算符;参见上文)
- 为锁创建一个SBRM帮助器类是值得的:
现在您可以创建一个同步作用域,如class Lock { pthread_mutex_t & m; public: explicit Lock(pthread_mutex_t & _m) : m(_m) { pthread_mutex_lock(&m); } ~Lock() { pthread_mutex_unlock(&m); } };
{Lock lk(mutex);/*…*/}
至于问题2:通过锁定互斥锁来序列化并发访问。其中一个竞争线程将在获取互斥锁时休眠。您已经掌握了基本知识,但我会更进一步,将互斥锁本身包装在自己的RAII包装器中,例如:
#include <deque>
#include "pthread.h"
class ProtectedMutex
{
pthread_mutex_t &mutex;
public:
ProtectedMutex(pthread_mutex_t &m)
: mutex(m);
{
pthread_mutex_lock(&mutex);
}
~ProtectedMutex()
{
pthread_mutex_unlock(&mutex);
}
};
template <class T>
class ProtectedBuffer {
std::deque<T> buffer;
pthread_mutex_t mutex;
public:
void add_back(T data) {
ProtectedMutex m(mutex);
buffer.push_back(data);
}
void get_front(T &data) {
ProtectedMutex m(mutex);
data = buffer.front();
buffer.pop_front();
}
};
#包括
#包括“pthread.h”
类ProtectedMutex
{
pthread_mutex_t&mutex;
公众:
ProtectedMutex(pthread\u mutex\u t&m)
:互斥(m);
{
pthread_mutex_lock(&mutex);
}
~ProtectedMutex()
{
pthread_mutex_unlock(&mutex);
}
};
模板
类ProtectedBuffer{
std::deque缓冲区;
pthread_mutex_t mutex;
公众:
void add_back(T数据){
ProtectedMutex m(互斥);
缓冲区。推回(数据);
}
void get_front(T&data){
ProtectedMutex m(互斥);
data=buffer.front();
buffer.pop_front();
}
};
“将结果放入主线程定期轮询的缓冲区”-CPU浪费和延迟
“我走错方向了吗?”-是的。我不知道您的系统对辅助线程GUI线程通信有什么支持,但总是有PostMessage()API
当然,您需要一个缓冲区类,其中包含用于串行rx数据的数据成员和执行协议/“处理数据”的方法。你不需要太多其他东西。在第二个线程中,创建一个缓冲区类实例。加载它,处理数据和PostMessage/disp
#include <deque>
#include <mutex>
#include <condition_variable>
#include <stdexcept>
template <class T>
class ProtectedBuffer {
std::deque<T> buffer;
std::mutex mtx;
std::condition_variable empty_cnd;
void get_front_i(T &data) {
data = buffer.front();
buffer.pop_front();
}
public:
void add_back(T data) {
std::lock_guard<std::mutex> g(mtx);
bool was_empty = buffer.empty();
buffer.push_back(data);
if (was_empty) empty_cnd.notify_one();
}
void get_front_check(T &data) {
std::lock_guard<std::mutex> g(mtx);
if (buffer.empty()) throw std::underflow_error("no data");
get_front_i(data);
}
void get_front_block(T &data) {
std::lock_guard<std::mutex> g(mtx);
std::unique_lock<std::mutex> u(mtx);
while (buffer.empty()) empty_cnd.wait(u);
get_front_i(data);
if (!buffer.empty()) empty_cnd.notify_one();
}
};