gpt4 book ai didi

c++ - 将互斥保护构建到 C++ 类中的线程安全方法?

转载 作者:太空狗 更新时间:2023-10-29 19:53:42 24 4
gpt4 key购买 nike

我正在尝试用 C++ 为我正在处理的项目实现一个生产者/消费者模型多线程程序。基本思想是主线程创建第二个线程来观察串行端口是否有新数据,处理数据并将结果放入主线程定期轮询的缓冲区中。我以前从未编写过多线程程序。我已经阅读了很多教程,但它们都是用 C 语言编写的。我认为我已经掌握了基本概念,但我正在尝试对其进行 C++ 化。对于缓冲区,我想创建一个内置互斥保护的数据类。这就是我想出的。

1) 我是不是用错了方法?有没有更智能的方法来实现 protected 数据类?

2) 如果两个线程试图同时调用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);
}
};

编辑:感谢所有伟大的建议。我试图在下面实现它们。我还添加了一些错误检查,因此如果线程以某种方式设法尝试两次锁定同一个互斥体,它将优雅地失败。我想。

#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_mutex_init 初始化 mutex在构造函数中,并在析构函数中使用 pthread_mutex_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:并发访问是通过锁定互斥锁的方式实现序列化的。竞争线程之一将在获取互斥锁时休眠。

关于c++ - 将互斥保护构建到 C++ 类中的线程安全方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11640681/

24 4 0