私が取り組んでいるプロジェクトのために、生産者/消費者モデルのマルチスレッド プログラムを C++ で実装しようとしています。基本的な考え方は、メイン スレッドが 2 番目のスレッドを作成してシリアル ポートで新しいデータを監視し、データを処理して、メイン スレッドによって定期的にポーリングされるバッファに結果を格納するというものです。私はこれまでマルチスレッドプログラムを書いたことがありません。たくさんのチュートリアルを読んできましたが、それらはすべて C で書かれています。基本的な概念は理解できたと思いますが、それを c++ 化しようとしています。バッファーについては、ミューテックス保護が組み込まれたデータ クラスを作成したいと考えています。これが私が思いついたものです。
1) 私はこれについて間違った方法で行っていますか? 保護されたデータ クラスを実装するよりスマートな方法はありますか?
ProtectedBuffer::add_back()
2) 2 つのスレッドが同時に呼び出そうとすると、次のコードはどうなりますか?
#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);
}
};
編集:すべての素晴らしい提案をありがとう。以下にそれらを実装しようとしました。また、いくつかのエラー チェックを追加したので、スレッドが何らかの方法で同じミューテックスを 2 回ロックしようとすると、正常に失敗します。おもう。
#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;
}
};