如何正确同步这两个线程?
How can I syncronize these two threads properly?
我想正确同步不同的线程,但到目前为止,我只能编写一个不优雅的解决方案。有人可以指出我如何改进以下代码吗?
typedef void (*func)();
void thread(func func1, func func2, int& has_finished, int& id) {
has_finished--;
func1();
has_finished++;
while (has_finished != 0) std::cout << "thread " << id << " waitingn";
std::cout << "thread" << id << "resumingn";
func2();
}
int main() {
int has_finished(0), id_one(0), id_two(1);
std::thread t1(thread, fun, fun, std::ref(has_finished), std::ref(id_one));
std::thread t2(thread, fun, fun, std::ref(has_finished), std::ref(id_two));
t1.join();
t2.join();
};
程序的要点由函数thread
描述。 该函数由两个std::thread
执行。该函数接受两个长时间运行的函数func1
和func2
以及两个 int 引用作为参数。线程应仅在所有线程退出func1
后调用func2
。参数has_finished
用于协调不同的线程:输入函数后,has_arguments
为零。然后,每个std::thread
递减该值并调用长时间运行的函数func1
。离开func1
后,has_finished
再次递增。只要此值不是其原始值零,线程就会等待。然后,每个线程都在func2
.主函数显示在末尾。
如何更好地协调两个线程?我想使用std::mutex
和std::condition_variable
,但不知道如何正确使用它们?有人知道我如何改进程序吗?
不要自己写这个。这种同步称为"锁存器"(或更一般的"屏障"(,它可以通过各种库和C++并发 TS 获得。(它也可能以某种形式进入C++20。
例如,使用 Boost 中的版本:
#include <iostream>
#include <thread>
#include <boost/thread/latch.hpp>
void f(boost::latch& c) {
std::cout << "Doing work in round 1n";
c.count_down_and_wait();
std::cout << "Doing work in round 2n";
}
int main() {
boost::latch c(2);
std::thread t1(f, std::ref(c)), t2(f, std::ref(c));
t1.join();
t2.join();
}
由于争用条件,您选择的方法实际上不起作用,并导致未定义的行为。正如您所推测的,您需要一个条件变量。
下面是一个Gate
类,演示如何使用条件变量来实现一个门,该门在继续之前等待一定数量的线程到达它:
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <sstream>
#include <utility>
#include <cassert>
struct Gate {
public:
explicit Gate(unsigned int count = 2) : count_(count) { } // How many threads need to reach the gate before it unlocks
Gate(Gate const &) = delete;
void operator =(Gate const &) = delete;
void wait_for_gate();
private:
int count_;
::std::mutex count_mutex_;
::std::condition_variable count_gate_;
};
void Gate::wait_for_gate()
{
::std::unique_lock<::std::mutex> guard(count_mutex_);
assert(count > 0); // Count being 0 here indicates an irrecoverable programming error.
--count_;
count_gate_.wait(guard, [this](){ return this-> count_ <= 0; });
guard.unlock();
count_gate_.notify_all();
}
void f1()
{
::std::ostringstream msg;
msg << "In f1 with thread " << ::std::this_thread::get_id() << 'n';
::std::cout << msg.str();
}
void f2()
{
::std::ostringstream msg;
msg << "In f2 with thread " << ::std::this_thread::get_id() << 'n';
::std::cout << msg.str();
}
void thread_func(Gate &gate)
{
f1();
gate.wait_for_gate();
f2();
}
int main()
{
Gate gate;
::std::thread t1{thread_func, ::std::ref(gate)};
::std::thread t2{thread_func, ::std::ref(gate)};
t1.join();
t2.join();
}
希望这段代码的结构看起来足够像你的代码,这样你就可以理解这里发生了什么。从阅读您的代码来看,您似乎正在寻找要执行的所有线程func1
,然后func2
.您不希望func2
在任何线程执行func1
时运行。
这可以被认为是一个门,所有线程都在等待到达"完成的func1"位置,然后再继续运行func2。
我在自己的本地版本的编译器资源管理器上测试了此代码。
另一个答案中闩锁的主要缺点是它还不是标准C++。我的Gate
类是另一个答案中提到的锁存类的简单实现,它是标准C++。
条件变量的基本工作方式是解锁互斥锁,等待通知,然后锁定该互斥锁并测试条件。如果条件为 true,则它将继续而不解锁互斥锁。如果条件为 false,则重新开始。
因此,在条件变量说条件为真之后,您必须执行任何您需要执行的操作,然后解锁互斥锁并通知所有人您已完成此操作。
此处的互斥锁保护共享计数变量。每当有共享值时,都应使用互斥锁保护它,以便任何线程都无法看到处于不一致状态的值。条件是线程可以等待该计数达到 0,表示所有线程都已递减 count 变量。
- 在两个线程上读/写 64 位,无互斥/锁定/原子
- 如果两个线程相互依赖,则 cpp 线程连接应使用连接导致死锁
- 两个线程一个使用流 Api,另一个线程创建文件失败并出现错误ERROR_SHARING_VIOLATION
- 简单使用 std::atomic 在两个线程之间共享数据
- 如何使用 pthreads 以正确的方式设置两个线程之一的优先级
- 曼德布洛特 从一个线程被反复使用变为两个线程
- C++ 两个线程,共享几个整数变量
- 如何正确同步这两个线程?
- 两个线程尝试将一些数据读/写到数据库中表的同一行中
- 两个线程的公共资源 - 同步足够吗?
- 如果两个线程调用同一个函数,但函数中的所有变量都是局部变量,我还需要担心线程之间共享数据吗?
- 当两个线程同时尝试在同一静音上尝试try_lock()时会发生什么
- C 带有两个线程的boost async_read vs
- 使用 Poco:Condition 唤醒两个线程
- C 两个线程一个用于输入,一个用于输出
- 将两个线程同步到同一个计时器
- 全局变量的最终值,该变量正在通过两个线程进行增量
- C++中两个线程的互斥体
- Qthread char阵列在两个线程之间传递后被摧毁
- 如何使用CPP中使用一个对象运行同一类的两个线程