英文:
Is there a way to use std::condition_variable::wait(lock, pred) without a lambda?
问题
我找到了在线上解释如何使用std::condition_variable
解决生产者-消费者问题的代码:使用C++中的条件变量解决生产者-消费者问题
#include <condition_variable> // std::condition_variale
#include <cstdlib>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
std::mutex g_mutex;
std::condition_variable g_cv;
bool g_ready = false;
int g_data = 0;
int produceData() {
int randomNumber = rand() % 1000;
std::cout << "produce data: " << randomNumber << "\n";
return randomNumber;
}
void consumeData(int data) { std::cout << "receive data: " << data << "\n"; }
void consumer() {
int data = 0;
while (true) {
std::unique_lock<std::mutex> ul(g_mutex);
g_cv.wait(ul, []() { return g_ready; });
consumeData(g_data);
g_ready = false;
ul.unlock();
g_cv.notify_one();
}
}
void producer() {
while (true) {
std::unique_lock<std::mutex> ul(g_mutex);
g_data = produceData();
g_ready = true;
ul.unlock();
g_cv.notify_one();
ul.lock();
g_cv.wait(ul, []() { return g_ready == false; });
}
}
void consumerThread(int n) { consumer(); }
void producerThread(int n) { producer(); }
int main() {
int times = 100;
std::thread t1(consumerThread, times);
std::thread t2(producerThread, times);
t1.join();
t2.join();
return 0;
}
我的代码有效,但我的编码标准规定我不允许使用lambda表达式。我如何在wait()
中不使用lambda表达式来使用此代码?
我尝试了以下方法,但它没有起作用:
- 使用普通的
bool
wait(g_ready)
英文:
I found this code online explaining how to use a std::condition_variable
to solve the Producer-Consumer Problem: Producer-Consumer Problem Using Condition Variable in C++
#include <condition_variable> // std::condition_variale
#include <cstdlib>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
std::mutex g_mutex;
std::condition_variable g_cv;
bool g_ready = false;
int g_data = 0;
int produceData() {
int randomNumber = rand() % 1000;
std::cout << "produce data: " << randomNumber << "\n";
return randomNumber;
}
void consumeData(int data) { std::cout << "receive data: " << data << "\n"; }
void consumer() {
int data = 0;
while (true) {
std::unique_lock<std::mutex> ul(g_mutex);
g_cv.wait(ul, []() { return g_ready; });
consumeData(g_data);
g_ready = false;
ul.unlock();
g_cv.notify_one();
}
}
void producer() {
while (true) {
std::unique_lock<std::mutex> ul(g_mutex);
g_data = produceData();
g_ready = true;
ul.unlock();
g_cv.notify_one();
ul.lock();
g_cv.wait(ul, []() { return g_ready == false; });
}
}
void consumerThread(int n) { consumer(); }
void producerThread(int n) { producer(); }
int main() {
int times = 100;
std::thread t1(consumerThread, times);
std::thread t2(producerThread, times);
t1.join();
t2.join();
return 0;
}
My code works, but my coding standard says I'm not allowed to use lambdas.
How can I use this code without using lambdas in wait()
?
I've tried the following, but it didn't work:
- use a normal
bool
wait(g_ready)
答案1
得分: 8
Disallowing lambdas in a coding standard has been criticized by commenters. Lambdas are essentially a convenient way to create types with a call operator, which can also be done manually.
使用可调用结构的解决方案
Lambda表达式:
[]() { return g_ready; }
大致对应于:
struct g_ready_checker {
bool operator()() const noexcept {
return g_ready;
}
};
然后可以执行以下操作:
g_cv.wait(ul, g_ready_checker{});
我们还可以将g_ready_checker
转化为一个带有<bool DesiredValue>
参数的类模板,或者将g_ready
的值存储为类成员变量。
使用自由函数的解决方案
或者,由于这个lambda没有捕获任何东西,您还可以编写一个自由函数,可能作为一个模板:
template <bool DesiredValue>
bool is_g_ready() {
return g_ready == DesiredValue;
}
/* ... */
g_cv.wait(ul, &is_g_ready<true>);
/* ... */
g_cv.wait(ul, &is_g_ready<false>);
在这里,我们为wait
提供了一个谓词,它是一个函数指针。请注意,std::condition_variable_wait
的Predicate
模板参数不仅限于lambda,它接受任何可调用的东西,返回值可转换为bool
。
英文:
As commenters have pointed out, disallowing lambdas is a dubious decision for a coding standard. Regardless, lambdas are just convenience syntax for creating types with a call operator, which you could do by hand.
Solution with callable struct
The lambda expression:
[]() { return g_ready; }
roughly translates into
struct g_ready_checker {
bool operator()() const noexcept {
return g_ready;
}
};
You could then do the following:
g_cv.wait(ul, g_ready_checker{});
We can also turn g_ready_checker
into a class template with a <bool DesiredValue>
parameter, or we could store the value g_ready
is meant to have as a class member.
Solution with free function
Or alternatively, since this lambda isn't capturing anything, you could also write a free function, possibly as a template:
template <bool DesiredValue>
bool is_g_ready() {
return g_ready == DesiredValue;
}
/* ... */
g_cv.wait(ul, &is_g_ready<true>);
/* ... */
g_cv.wait(ul, &is_g_ready<false>);
Here, we provide wait
with a predicate which is a function pointer. Note that the Predicate
template parameter of std::condition_variable_wait
is not restricted to lambdas, it accepts anything callable which returns something convertible bool
.
答案2
得分: 4
以下是已翻译的内容:
这里有一种避免使用 lambda 表达式的方法。
鉴于 std::condition_variable::wait
提供了以下两种重载版本:
void wait( std::unique_lock<std::mutex>& lock );
template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );
如果您有一个 std::condition_variable cv
,那么调用 cv.wait(lock, stop_waiting);
等同于:
while (!stop_waiting()) {
cv.wait(lock);
}
因此,只需不提供第二个参数 stop_waiting
(在其中可以提供 lambda 表达式),而是调用 wait(lock)
并在循环中手动检查条件。将 g_cv.wait(ul, []() { return g_ready; });
更改为不使用 lambda 将简单地如下所示:
while(!g_ready) {
g_cv.wait(ul);
}
英文:
Here's one way to avoid a lambda.
Given that std::condition_variable::wait
offers both these overloads:
void wait( std::unique_lock<std::mutex>& lock );
template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );
If you have some std::condition_variable cv
, then calling cv.wait(lock, stop_waiting);
is equivalent to:
while (!stop_waiting()) {
cv.wait(lock);
}
So just don't provide the second argument stop_waiting
(where one might provide a lambda) and instead call wait(lock)
and check your condition manually in a loop. Changing g_cv.wait(ul, []() { return g_ready; });
to not use a lambda would simply look like this:
while(!g_ready) {
g_cv.wait(ul);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论