variable visibility in thread synchronization - c++

struct Info {
int a;
int b;
};
class A {
public:
A() {
_info = new Info;
_info->a = 1;
_info->b = 1;
}
void update()
{
std::lock_guard<std::mutex> l(_m);
_info->a = 2;
_info->b = 3;
}
Info* get_info() {
std::lock_guard<std::mutex> l(_m);
return _info;
}
private:
mutable std::mutex _m;
Info* _info;
};
A a;
// in thread 1
a.update();
// in thread 2
Info* i = a.get_info();
std::cout<<i->a<<" "<<i->b<<std::endl;
Does it possible to print 1 3 or 2 1 ?

This is unspecified/undefined behavior
The objects being accessed are not protected by a mutex. The mutex is being held only long enough to read the pointer. The mutex is not held while accessing the contents of the pointer, as such the mutex offers no synchronization with update().

Related

Dereferencing a pointer by multiple threads

In the example below, suppose I have a multithreaded queue i.e. supports multiple writes and reads from different threads (e.g. using mutex). We can see that 1. the pointer this as well as 2. the shared pointer m_mulque are passed to the readers and writers and my question is: Dereferencing the pointers this and m_mulque is thread safe or not? In other words is my following code thread safe or not meaning should I worry about any undefined behaviour if I run this please?
#include <mutex>
#include <queue>
struct multithreaded_queue
{
void push(const std::size_t i)
{
std::lock_guard lock(m_mutex);
m_queue.push(i);
};
void try_pop()
{
std::lock_guard lock(m_mutex);
m_queue.pop();
};
private:
std::queue<std::size_t> m_queue;
mutable std::mutex m_mutex;
};
class example
{
public:
example()
{
m_mulque = std::make_shared<multithreaded_queue>();
};
void run()
{
auto writer = [this]()
{
for (std::size_t i = 0; i < 1000; i++)
{
m_mulque->push(i);
};
};
auto reader = [this]()
{
for (std::size_t i = 0; i < 1000; i++)
{
m_mulque->try_pop();
};
};
std::thread writer1(writer);
std::thread reader1(reader);
std::thread reader2(reader);
writer1.join();
reader1.join();
reader2.join();
};
private:
std::shared_ptr<multithreaded_queue> m_mulque;
};
int main(int argc, char* argv[])
{
example ex;
ex.run(); //Is this thread safe to call?
};

Writing a thread safe optimized Datastore class

I am trying to write a thread safe datastore class.
This class object is shared with between many threads in Generator and Consumer, where the class members can be set or get.
By calling setDatastore() the object is set for usage at different threads.
Below is my code,
#ifndef IF_DATA_STORE_H
#define IF_DATA_STORE_H
#include <mutex>
#include <shared_mutex>
#include <memory>
class DataType1{public:int value;};
class DataType2{public:int value;};
class DataStore
{
public:
DataStore(): _member1(), _member2(){}
~DataStore(){}
// for member1
void setMember1(const DataType1& val)
{
std::unique_lock lock(_mtx1); // no one can read/write!
_member1 = val;
}
const DataType1& getMember1() const
{
std::shared_lock lock(_mtx1); // multiple threads can read!
return _member1;
}
// for member2
void setMember2(const DataType2& val)
{
std::unique_lock lock(_mtx2); // no one can read/write!
_member2 = val;
}
const DataType2& getMember2() const
{
std::shared_lock lock(_mtx2); // multiple threads can read!
return _member2;
}
private:
mutable std::shared_mutex _mtx1;
mutable std::shared_mutex _mtx2;
DataType1 _member1;
DataType2 _member2;
// different other member!
};
// now see where data is generated/consumed!
class Generator
{
public:
void start(){/* start thread!*/}
void setDataStore(std::shared_ptr<DataStore> store)
{
_store = store;
}
void threadRoutine() //this is called from different thread and updating values
{
// some code...
{
_data.value = 10; // keep a local updated copy of data!
_store->setMember1(_data);
}
}
private:
std::shared_ptr<DataStore> _store;
DataType1 _data;
};
class Consumer
{
public:
void start(){/* start thread!*/}
void setDataStore(std::shared_ptr<DataStore> store)
{
_store = store;
}
void threadRoutine() // running a check on datastore every 1sec
{
// some code...
auto val = _store->getMember1();
// do something..
}
private:
std::shared_ptr<DataStore> _store;
};
// fianlly start all!
int main()
{
// somewhere in main thread
std::shared_ptr<DataStore> store;
Consumer c; Generator g;
c.setDataStore(store); c.start();
g.setDataStore(store); g.start();
}
#endif
Questions:
Is there any other way than creating multiple shared mutex for each member?
In Generator.threadRoutine() if I keep a local copy of DataType1 does this cause high memory issues (I see high cpu and memory) when this block called frequently, don't if this is the root cause of it.
Any other better way suggested?

Valgrind shows Leak_DefinitelyLost even after releasing the pointer

In some file called Tasks.h, I have the following function :-
void source_thread_func(BlockingQueue<Task> &bq, int num_ints)
{
std::cout<<"On source thread func"<<std::endl; // Debug
for (int i = 1; i <= num_ints; i++)
{
//Valgrind does not like this
std::unique_ptr<Task> task(new Task(i, i == num_ints));
std::cout<<"Pushing value = "<<i<<std::endl; // Debug
bq.push(task);
Task* tp = task.release();
assert (task.get() == nullptr);
delete tp;
}
}
and the relevant push function in the BlockingQueue is
void push(std::unique_ptr<T>& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
queue_.push(std::move(item));
mlock.unlock();
cond_.notify_one();
}
But, this still causes a leak when checking with Valgrind. Could you tell me where the leak is? I am attaching a screenshot of the valgrind result. How more can I delete this pointer?
Edit : Task doesn't contain a copy constructor (I've deleted it)
Further Edit : full example
//Tasks.h
namespace threadsx
{
class Task
{
public:
Task(int val, bool sentinel = false)
{
m_val = val;
Sent = sentinel;
}
int m_val;
int Sent;
//disable copying
Task (const Task&) = delete;
};
void source_thread_func(BlockingQueue<Task> &bq, int num_ints)
{
std::cout<<"On source thread func"<<std::endl; // Debug
for (int i = 1; i <= num_ints; i++)
{
std::unique_ptr<Task> task(new Task(i, i == num_ints));
std::cout<<"Pushing value = "<<i<<std::endl; // Debug
bq.push(task);
Task* tp = task.release();
assert (task.get() == nullptr);
delete tp;
}
}
}
+++++++++++++++++++++++++++++++
///BlockingQueue.h
namespace threadsx
{
// -- Custom Blocking Q
template <typename T>
class BlockingQueue
{
private:
std::queue<std::unique_ptr<T>> queue_;
std::mutex mutex_;
std::condition_variable cond_;
void push(std::unique_ptr<T>& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
queue_.push(std::move(item));
mlock.unlock();
cond_.notify_one();
}
BlockingQueue()=default;
BlockingQueue(const BlockingQueue&) = delete; // disable copying
BlockingQueue& operator=(const BlockingQueue&) = delete; // disable assignment
};
}
+++++++++++++++++++++++++++++++
//main.cpp
int main(int argc, char **argv)
{
int num_ints = 30;
int threshold = 5;
threadsx::BlockingQueue<threadsx::Task> q;
std::vector<int> t;
std::thread source_thread(threadsx::source_thread_func, std::ref(q), num_ints);
if(source_thread.joinable())
source_thread.join();
return 0;
}
The program that you show does not delete the Task that was allocated. push moves the ownership away from task, so tp is always null.
The ownership of the resource is transferred into queue_, and how that pointer is leaked (assuming valgrind is correct) is not shown in the example program.
Few quality issues:
As pointed out in the comments, it is usually a bad design to pass unique pointers by non-const reference. Pass by value when you intend to transfer ownership.
I've deleted the copy constructor on Task. Would passing by value still work?
Whether Task is copyable is irrelevant to whether a unique pointer can be passed by value. Unique pointer is movable regardless of the type of the pointed object, and therefore can be passed by value.
Don't release from a unique pointer just in order to delete the memory. Simply let the unique pointer go out of scope - its destructor takes care of deletion.
You are not allowed to delete the raw task, since the ownership is no longer yours.
void source_thread_func(BlockingQueue<Task>& bq, int num_ints)
{
std::cout<<"On source thread func"<<std::endl; // Debug
for (int i = 1; i <= num_ints; i++)
{
std::unique_ptr<Task> task = std::make_unique<Task>(i, i == num_ints);
bq.push(std::move(task));
}
}
Blocking Queue:
#include <memory>
#include <mutex>
#include <condition_variable>
#include <deque>
template <typename T>
class BlockingQueue {
public:
void push(std::unique_ptr<T>&& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
queue_.push_back(std::move(item));
cond_.notify_one();
}
std::unique_ptr<T> pop()
{
std::unique_lock<std::mutex> mlock(mutex_);
if (queue_.empty()) {
cond_.wait(mlock, [this] { return !queue_.empty(); });
}
std::unique_ptr<T> ret = std::unique_ptr<T>(queue_.front().release());
queue_.pop_front();
return ret;
}
private:
std::deque<std::unique_ptr<T>> queue_;
std::mutex mutex_;
std::condition_variable cond_;
};
If you want to spare yourself the headache of std::move, use shared_ptr instead

boost::thread passing data between threads

I am attempting to pass data between two sub classes of my main threading class using boost::thread. I am very new to multithreading and in a bit over my head. Right now the code produces the following repeatedly.
Reader Api: 0
Below is my class andd subclass definitions. The threading class is a singleton.
class threading
{
public:
static threading *Instance();
void workerFunc();
void workerFunc2();
void inputWorkerFunc(); // handles input processing
void producer();
void consumer();
int getGlobalVariable() // retrieves the value of globalVariable
{
return (globalVariable);
}
void setGlobalVariable(int set) // sets the value of globalVariable
{
globalVariable = set;
}
class Reader
{
public:
Reader(int waitTime) { _waitTime = waitTime;}
void operator() ()
{
threading *thread = threading::Instance();
int globalVariable = thread->getGlobalVariable();
for (int i=0; i < 10; i++)
{
logMsg("Reader Api: " +Ogre::StringConverter::toString(globalVariable));
// usleep(_waitTime);
boost::this_thread::sleep(boost::posix_time::microseconds(_waitTime));
}
return;
}
private:
int _waitTime;
};
class Writer
{
public:
Writer(int variable, int waitTime)
{
_writerVariable = variable;
logMsg("Writer Variable: " +Ogre::StringConverter::toString(_writerVariable));
_waitTime = waitTime;
}
void operator () ()
{
logMsg("Writer Variable: " +Ogre::StringConverter::toString(_writerVariable));
threading *thread = threading::Instance();
int globalVariable = thread->getGlobalVariable();
for (int i=0; i < 10; i++)
{
// usleep(_waitTime);
boost::this_thread::sleep(boost::posix_time::microseconds(_waitTime));
logMsg("Waittime Variable: " +Ogre::StringConverter::toString(_waitTime));
// Take lock and modify the global variable
boost::mutex::scoped_lock lock(_writerMutex);
globalVariable = _writerVariable;
thread->setGlobalVariable(globalVariable);
_writerVariable++;
// since we have used scoped lock,
// it automatically unlocks on going out of scope
}
logMsg("Writer Variable: " +Ogre::StringConverter::toString(_writerVariable));
// thread->setGlobalVariable(globalVariable);
}
private:
int _writerVariable;
int _waitTime;
static boost::mutex _writerMutex;
};
protected:
threading();
threading(const threading&);
threading& operator= (const threading&);
private:
static threading *pInstance;
int globalVariable;
boost::mutex mutex;
boost::condition_variable condvar;
typedef boost::unique_lock<boost::mutex> lockType;
double value;
int count;
};
Here is how I am calling the classes in my main code:
threading *thread = threading::Instance();
threading::Reader reads(100);
threading::Writer writes1(100, 200);
threading::Writer writes2(200, 200);
boost::thread readerThread(reads);
boost::thread writerThread1(writes1);
boost::this_thread::sleep(boost::posix_time::microseconds(100));
boost::thread writerThread2(writes2);
readerThread.join();
writerThread1.join();
writerThread2.join();
You're obviously missing a decent synchronization mechanism like a (global) mutex, to prevent race conditions with this code:
static std::mutex globalVariableProtector;
int getGlobalVariable() // retrieves the value of globalVariable
{
std::lock_guard<std::mutex> lock(globalVariableProtector);
return (globalVariable);
}
void setGlobalVariable(int set) // sets the value of globalVariable
{
std::lock_guard<std::mutex> lock(globalVariableProtector);
globalVariable = set;
}
Moreover, you actually should consider to place that variable into the producer thread's class, and provide getter/setter functions for it, instead of using a global variable.
I've been sharing the current standard references, rather boost. Boost may have their own mechanisms of lock_guards and Synchronized Data Structures, if you for reason can't use the current c++ standard.

Static initialization in c++ and thread safety

Static initialization of class instances is not thread-safe. The code below is an example of what not to do :
extern int computesomething();
class cachedcomputation
{
public:
cachedcomputation()
{
result = computesomething();
}
int result;
};
void usecached()
{
static cachedcomputation c;
// use of c.result - may break
}
However, would the code below be thread-safe ? (Ignoring the ugliness of the solution) When or why would it break ?
extern int computesomething();
class cachedcomputation
{
public:
cachedcomputation()
{
if(0==InterlockedCompareExchange(&mutex, 1, 0))
{
// first thread
result = computesomething();
InterlockedExchange(&mutex, 2);
}
else
{
// other thread - spinlock until mutex==2
while(2!=InterlockedCompareExchange(&mutex, 2, 2)){}
}
}
int result;
private:
long mutex;
};
void usecached()
{
static cachedcomputation c;
// use of c.result - ???
}
You need to:
initialize your "mutex"
reset "mutex" at the end of if block: InterlockedExchange(&mutex, 0)
optionally convert if-statement to while, so your code would block until "mutex" is unlocked