I am trying to learn threading in c++.
I have implemented Bounded Buffer - producer/consumer Simulation, but I am facing some error in passing class variable in the lambda expression.
I am facing issue in passing one of the class variable in lambda expression inside one of the class member functions. I have tried passing my variable in capture clause and parameter , but I am still getting error.
class example {
private :
vector<int> storage;
public :
void outsideCallFunction(int x) {
auto lambdaFun = [&storage] () {
if(storage.size() > 50) return true; // FACING ISSUE HERE , NOT ABLE TO ACCESS storage variable in side the lambda function, I have tried many different ways of passing as parameter, as
else return false;
// using lambdaFun ahead in the code
}
}
}
Please go ahead and copy paste the code in your editor. I am facing issue in lineNumber 21 and 30 ( both are same issue actually ).
I am new to c++ lambda expressions, I would be grateful if someone can help me understand the problem and explain the solution. Thank you in advance.
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <thread>
using namespace std;
class ProducerConsumerSimulation {
private :
vector<int> storage; // common storage, where we store data, which is critical section, so we need to use mutex.
mutex storageMutex;
condition_variable storageConditionVariable;
public :
void publish(int x) {
/*
if Storage is having 50, dont push any more elements, wait for consumer to consume some data.
*/
unique_lock<mutex> storageUniqueLock(storageMutex);
// how to pass storage in lambda
storageConditionVariable.wait( storageUniqueLock, []() {return storage.size() > 50 ? false : true; } ); // if the storage is full , then wait for consumer to consume it
storage.push_back(x);
storageConditionVariable.notify_one();
}
int consume() {
/*
consume data, until there is some data in storage, otherwise wait for producer to push data.
*/
unique_lock<mutex> storageUniqueLock(storageMutex);
// how to pass "storage" in lambda
storageConditionVariable.wait( storageUniqueLock , []() { return storage.size() > 0 ? true : false ; });
int returnVal = storage.back();
storage.pop_back();
storageConditionVariable.notify_one();
return returnVal;
}
};
void publishMethod(ProducerConsumerSimulation &simulationObject) { // publisher is one thread that is publishing data object
for(int i = 0 ; i < 100 ; i++) {
int randomNumber = rand() % 20;
simulationObject.publish(randomNumber);
}
}
void consumeMethod(ProducerConsumerSimulation &simulationObject) { // consumer is one thread which is consuming data from object
for(int i = 0 ; i < 100 ; i++) {
int result = simulationObject.consume();
cout << " consumer thread got result " << result << endl;
}
}
int main() {
ProducerConsumerSimulation simulationObject;
thread publisherThread(publishMethod, std::ref(simulationObject));
thread consumerThread(consumeMethod, std::ref(simulationObject));
publisherThread.join();
}
I have tried passing class variable in CAPTURE CLAUSE [] and in PARAMETER () . But didn't work out.
Here's the working code:
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <thread>
using namespace std;
class ProducerConsumerSimulation {
private :
vector<int> storage; // common storage, where we store data, which is critical section, so we need to use mutex.
mutex storageMutex;
condition_variable storageConditionVariable;
public :
void publish(int x) {
/*
if Storage is having 50, dont push any more elements, wait for consumer to consume some data.
*/
unique_lock<mutex> storageUniqueLock(storageMutex);
// how to pass storage in lambda
storageConditionVariable.wait( storageUniqueLock, [&]() {return storage.size() > 50 ? false : true; } ); // if the storage is full , then wait for consumer to consume it
storage.push_back(x);
storageConditionVariable.notify_one();
}
int consume() {
/*
consume data, until there is some data in storage, otherwise wait for producer to push data.
*/
unique_lock<mutex> storageUniqueLock(storageMutex);
// how to pass "storage" in lambda
storageConditionVariable.wait( storageUniqueLock , [&]() { return storage.size() > 0 ? true : false ; });
int returnVal = storage.back();
storage.pop_back();
storageConditionVariable.notify_one();
return returnVal;
}
};
void publishMethod(ProducerConsumerSimulation &simulationObject) { // publisher is one thread that is publishing data object
for(int i = 0 ; i < 100 ; i++) {
int randomNumber = rand() % 20;
simulationObject.publish(randomNumber);
}
}
void consumeMethod(ProducerConsumerSimulation &simulationObject) { // consumer is one thread which is consuming data from object
for(int i = 0 ; i < 100 ; i++) {
int result = simulationObject.consume();
cout << " consumer thread got result " << result << endl;
}
}
int main() {
ProducerConsumerSimulation simulationObject;
thread publisherThread(publishMethod, std::ref(simulationObject));
thread consumerThread(consumeMethod, std::ref(simulationObject));
publisherThread.join();
}
C++ lambdas require that you specify the captures
, if you don't then the lambda won't be able to access variables outside its scope but only its provided arguments.
There are many ways to use captures with Lambdas, I suggest checking the C++ documentation on Lambdas.
But in this case, you needed to add the &
symbol inside the []
(the captures
of the lambda) to gain access to the storage
variable by reference.
Or you could also use the =
symbol since you don't need to modify the storage
variable but I still suggest using references since doing a copy of the storage
variable every time could negatively influence the program speed.
Hope this solves your issue.