我不知道这是否是一个好习惯,但是我正在处理输入数据的实时流,并以锁步的方式使用pthread来一次允许一个线程同时执行不同的操作。这是每个线程的程序流:
void * my_thread() {
pthread_mutex_lock(&read_mutex);
/*
read data from a stream such as stdin into global buffer
*/
pthread_mutex_lock(&operation_mutex);
pthread_mutex_unlock(&read_mutex);
/*
perform some work on the data you read
*/
pthread_mutex_lock(&output_mutex);
pthread_mutex_unlock(&operation_mutex);
/*
Write the data to output such as stdout
*/
pthread_mutex_unlock(&output_mutex);
}
我知道有pthread条件锁,但是我的方法是好主意还是坏主意?我在各种大小的流上对此进行了测试,我试图考虑一些极端情况,以使这种僵局,产生竞争状况或同时发生这两种情况。我知道互斥锁不能保证线程顺序的执行,但是我需要帮助来考虑可能会破坏这种情况的情况。
更新:
我放弃了这个,但是最近有一段时间重新考虑这个。我使用C ++线程和互斥体重写了代码。我正在尝试使用条件变量,但没有这种运气。这是我解决问题的方法:
void my_thread_v2() {
//Let only 1 thread read in at a time
std::unique_lock<std::mutex> stdin_lock(stdin_mutex);
stdin_cond.wait(stdin_lock);
/*
Read from stdin stream
*/
//Unlock the stdin mutex
stdin_lock.unlock();
stdin_cond.notify_one();
//Lock step
std::unique_lock<std::mutex> operation_lock(operation_mutex);
operation_cond.wait(operation_lock);
/*
Perform work on the data that you read in
*/
operation_lock.unlock();
operation_cond.notify_one();
std::unique_lock<std::mutex> stdout_lock(stdout_mutex);
stdout_cond.wait(stdout_lock);
/*
Write the data out to stdout
*/
//Unlock the stdout mutex
stdout_lock.unlock();
stdout_cond.notify_one();
}
我知道这段代码的问题是,没有办法表明第一个条件。我绝对不理解条件变量的正确使用。我看了有关cpp引用的各种示例,但似乎无法摆脱这种想法,即最初的方法也许是我要做的唯一方法是锁定线程。有人可以阐明这一点吗?
更新2:
因此,我实现了一个简单的Monitor类,该类利用C ++ condition_variable
和unique_lock
:
class ThreadMonitor{
public:
ThreadMonitor() : is_occupied(false) {}
void Wait() {
std::unique_lock<std::mutex> lock(mx);
while(is_occupied) {
cond.wait(lock);
}
is_occupied = true;
}
void Notify() {
std::unique_lock<std::mutex> lock(mx);
is_occupied = false;
cond.notify_one();
}
private:
bool is_occupied;
std::condition_variable cond;
std::mutex mx;
};
这是我的初始方法,假设我有三个分别称为ThreadMonitor
,stdin_mon
和operation_mon
的{{1}}:
stdout_mon
问题是数据仍然被破坏,所以我不得不回到锁步的原始逻辑:
void my_thread_v3() {
//Let only 1 thread read in at a time
stdin_mon.Wait();
/*
Read from stdin stream
*/
stdin_mon.Notify();
operation_mon.Wait();
/*
Perform work on the data that you read in
*/
operation_mon.Notify();
stdout_mon.Wait();
/*
Write the data out to stdout
*/
//Unlock the stdout
stdout_mon.notify();
}
我开始怀疑,如果线程顺序很重要,这是处理它的唯一方法。我还质疑使用监视器void my_thread_v4() {
//Let only 1 thread read in at a time
stdin_mon.Wait();
/*
Read from stdin stream
*/
operation_mon.Wait();
stdin_mon.Notify();
/*
Perform work on the data that you read in
*/
stdout_mon.Wait();
operation_mon.Notify();
/*
Write the data out to stdout
*/
//Unlock the stdout
stdout_mon.notify();
}
而不是仅使用互斥锁的好处是什么。
答案 0 :(得分:0)
您的方法存在的问题是,当另一个线程正在读取数据时,您仍然可以修改数据:
我假设您想允许多个线程读取同一数据而不会阻塞,但是一旦写入,数据就应受到保护。最后,在输出数据时,我们只是再次读取修改后的数据,因此可以再次并发执行此操作,但是需要防止同时写入。
与其拥有多个互斥锁实例,不如使用读/写互斥锁来做得更好:
最后一点是有问题的,因为C ++标准的线程支持库和pthreads库都不支持。
对于C ++ Boost,它提供了solution;如果您不想或不能(C!)使用boost,那么一种简单但可能不是最有效的方法就是保护通过另一个互斥锁获取写锁定:
非修改功能只能获取读锁而没有任何进一步的保护,与...没有任何冲突。
在C ++中,您更喜欢使用thread support library并另外免费获取与平台无关的代码,在C中,您将像以前一样使用标准的pthread互斥锁来保护获取写锁,并使用pthread的RW变体用于读写锁定。