使用 std::condition_variable 同步调用函数
Synchronized call of functions using std::condition_variable
又沉迷于学习并发,尝试解决this problem.
总之,我有一个class和3个功能。我需要同步他们的通话(需要打印 FirstSecondThird
)。
下面的代码会更清楚:
std::function<void()> printFirst = []() { std::cout << "First"; };
std::function<void()> printSecond = []() { std::cout << "Second"; };
std::function<void()> printThird = []() { std::cout << "Third"; };
class Foo {
std::condition_variable cv;
bool mfirst,msecond;
std::mutex mtx;
public:
Foo() {
mfirst = false;
msecond = false;
}
void first(std::function<void()> printFirst) {
std::unique_lock<std::mutex> l(mtx);
printFirst();
mfirst = true;
}
void second(std::function<void()> printSecond) {
std::unique_lock<std::mutex> l(mtx);
cv.wait(l, [this]{return mfirst == true; });
printSecond();
msecond = true;
}
void third(std::function<void()> printThird) {
std::unique_lock<std::mutex> l(mtx);
cv.wait(l, [this] {return (mfirst && msecond) == true; });
printThird();
}
};
int main()
{
Foo t;
std::thread t3((&Foo::third, t, printThird));
std::thread t2((&Foo::second, t, printSecond));
std::thread t1((&Foo::first, t, printFirst));
t3.join();
t2.join();
t1.join();
return 0;
}
猜猜我的输出是什么?它打印 ThirdSecondFirst
.
这怎么可能?这段代码不是容易死锁吗?我的意思是,当第一个线程在函数 second
中获取互斥锁时,它不会永远等待吗,因为现在获取了互斥锁,我们无法更改变量 mfirst
?
你有一个非常微妙的错误。
std::thread t3((&Foo::third, t, printThird));
此行不符合您的预期。它仅使用一个参数 printThird
初始化一个线程,而不是使用您指定的 3 个参数进行初始化。那是因为你不小心用了comma expression。结果,&Foo::third
和 t
被丢弃,成员函数甚至从未被调用。
您的代码中唯一调用的函数是 printFirst
、printSecond
和 printThird
。如果没有任何同步,它们可能会以任意顺序打印。您甚至可以获得交错输出。
std::thread t3{&Foo::third, t, printThird};
这是更正后的版本。大括号是为了避免编译器将其视为函数声明,因为 most vexing parse
附带说明,如评论中所述,您使用的条件变量是错误的。
又沉迷于学习并发,尝试解决this problem.
总之,我有一个class和3个功能。我需要同步他们的通话(需要打印 FirstSecondThird
)。
下面的代码会更清楚:
std::function<void()> printFirst = []() { std::cout << "First"; };
std::function<void()> printSecond = []() { std::cout << "Second"; };
std::function<void()> printThird = []() { std::cout << "Third"; };
class Foo {
std::condition_variable cv;
bool mfirst,msecond;
std::mutex mtx;
public:
Foo() {
mfirst = false;
msecond = false;
}
void first(std::function<void()> printFirst) {
std::unique_lock<std::mutex> l(mtx);
printFirst();
mfirst = true;
}
void second(std::function<void()> printSecond) {
std::unique_lock<std::mutex> l(mtx);
cv.wait(l, [this]{return mfirst == true; });
printSecond();
msecond = true;
}
void third(std::function<void()> printThird) {
std::unique_lock<std::mutex> l(mtx);
cv.wait(l, [this] {return (mfirst && msecond) == true; });
printThird();
}
};
int main()
{
Foo t;
std::thread t3((&Foo::third, t, printThird));
std::thread t2((&Foo::second, t, printSecond));
std::thread t1((&Foo::first, t, printFirst));
t3.join();
t2.join();
t1.join();
return 0;
}
猜猜我的输出是什么?它打印 ThirdSecondFirst
.
这怎么可能?这段代码不是容易死锁吗?我的意思是,当第一个线程在函数 second
中获取互斥锁时,它不会永远等待吗,因为现在获取了互斥锁,我们无法更改变量 mfirst
?
你有一个非常微妙的错误。
std::thread t3((&Foo::third, t, printThird));
此行不符合您的预期。它仅使用一个参数 printThird
初始化一个线程,而不是使用您指定的 3 个参数进行初始化。那是因为你不小心用了comma expression。结果,&Foo::third
和 t
被丢弃,成员函数甚至从未被调用。
您的代码中唯一调用的函数是 printFirst
、printSecond
和 printThird
。如果没有任何同步,它们可能会以任意顺序打印。您甚至可以获得交错输出。
std::thread t3{&Foo::third, t, printThird};
这是更正后的版本。大括号是为了避免编译器将其视为函数声明,因为 most vexing parse
附带说明,如评论中所述,您使用的条件变量是错误的。