As per cppreference document:
All member functions (including copy constructor and copy assignment)
can be called by multiple threads on different instances of shared_ptr
without additional synchronization even if these instances are copies
and share ownership of the same object.
As i understood from cppreference, you don't need to put synchronization as you are calling different member functions using different instances of shared_ptr which points to the same object.
Please correct me if i understood wrong.and also give small example to understand it clearly.
#include <iostream>
#include <memory>
#include <thread>
using namespace std;
class Demo
{
public:
int Value;
Demo():Value(10){}
void fun1()
{
for(int i=0; i<300000; i++)
{
Value = Value + i;
std::cout << "Value1 :" << Value << std::endl;
}
}
void fun2()
{
for(int i=0; i<300000; i++)
{
Value = Value + i;
std::cout << "Value2 :" << Value << std::endl;
}
}
void fun3()
{
for(int i=0; i<300000; i++)
{
Value = Value + i;
std::cout << "Value3 :" << Value << std::endl;
}
}
};
int main()
{
std::shared_ptr<Demo> ptr1(new Demo);
std::thread t1(&Demo::fun1, ptr1);
std::shared_ptr<Demo> ptr2(ptr1);
std::thread t2(&Demo::fun2, ptr2);
std::shared_ptr<Demo> ptr3(ptr2);
std::thread t3(&Demo::fun3, ptr3);
t1.join();
t2.join();
t3.join();
}
//output:
Getting random(asynchronized) output as shown below:
Value3 :70993659Value2 :
71000412
Value1 :71006910Value2 :
70993659Value1 :71013664
All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object.
shared_ptr's member functions can be called without synchronization. However, you still need to synchronize member function calls of the template type, i.e. Demo.
fun1, fun2 and fun3 are member of Demo, not member of shared_ptr. So you still need to use lock to protect them.
Yes, you need synchronization for both value_ and std::cout.
Beside that, the sum of the first 300,000 positive integers is: 45,000,000,000 (45 billion). X 3 threads is: 13.5 billion. To avoid undefined behavior when a signed integer exceeds INT_MAX (2,147,483,647), it is advisable to change its data type to unsigned integer and to use wider integer data types such as uint32_t and uint64_t.
Example:
#include <iostream>
#include <memory>
#include <thread>
#include <mutex>
class Demo
{
public:
uint64_t value_;
Demo() : value_(10) {}
void fun1()
{
for (uint32_t i = 0; i < 300000; i++)
{
std::lock_guard lock(mutex_);
value_ += i;
std::cout << "Value1 :" << value_ << std::endl;
}
}
void fun2()
{
for (uint32_t i = 0; i < 300000; i++)
{
std::lock_guard lock(mutex_);
value_ += i;
std::cout << "Value2 :" << value_ << std::endl;
}
}
void fun3()
{
for (uint32_t i = 0; i < 300000; i++)
{
std::lock_guard lock(mutex_);
value_ += i;
std::cout << "Value3 :" << value_ << std::endl;
}
}
protected:
std::mutex mutex_{};
};
int main()
{
std::shared_ptr<Demo> ptr1(new Demo);
std::thread t1(&Demo::fun1, ptr1);
std::shared_ptr<Demo> ptr2(ptr1);
std::thread t2(&Demo::fun2, ptr2);
std::shared_ptr<Demo> ptr3(ptr2);
std::thread t3(&Demo::fun3, ptr3);
t1.join();
t2.join();
t3.join();
}
Related
I have 2 code examples syncing 2 threads with std::barrier{2}. In one I create the barrier statically, and in one I create it dynamically. The 2nd way mimics the way I want to use the barrier - since number of threads - and hence the "size" of the barrier, is something I'll know only on runtime, making it impossible to declare it static.
My question is - why the static snippet works, where the dynamic snippet (using shared pointers) doesn't (it just hangs...)
My snippets are compiled and run with: clang++-15 -l pthread --std=c++20 demo.cpp && ./a.out (I've also used g++-11)
Updated (3rd snippet working! :) )
#include <barrier>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <vector>
// Working
// static std::barrier b{2};
// int task() {
// b.arrive_and_wait();
// std::cout << "start\n";
// b.arrive_and_wait();
// std::cout << "stop\n";
// return 0;
//}
// int main() {
// std::vector<std::future<int>> promises;
// for (int i = 0; i < 2; ++i) {
// auto promise = std::async(task);
// promises.push_back(std::move(promise)); // Why must I use std::move?
//}
// for (auto& promise : promises) {
// std::cout << promise.get() << std::endl;
//}
// return 0;
//}
// Not working (1) - reference
// int task(std::barrier<std::function<void()>>& b) {
// std::cout << "start\n";
// b.arrive_and_wait();
// std::cout << "stop\n";
// b.arrive_and_wait();
// return 0;
//}
// int main() {
// std::vector<std::future<int>> promises;
// std::barrier<std::function<void()>> barrier{2};
// for (int i = 0; i < 2; ++i) {
// auto promise = std::async(task, std::ref(barrier));
// promises.push_back(std::move(promise)); // Why must I use std::move?
//}
// for (auto& promise : promises) {
// std::cout << promise.get() << std::endl;
//}
// return 0;
//}
// Working!!
int task(std::shared_ptr<std::barrier<>> b) {
std::cout << "start\n";
b->arrive_and_wait();
std::cout << "stop\n";
b->arrive_and_wait();
return 0;
}
int main() {
std::vector<std::future<int>> promises;
auto barrier = std::make_shared<std::barrier<>>(2);
for (int i = 0; i < 2; ++i) {
auto promise = std::async(task, barrier);
promises.push_back(std::move(promise)); // Why must I use std::move?
}
for (auto& promise : promises) {
std::cout << promise.get() << std::endl;
}
return 0;
}
You're attempting to call a default-initialized std::function.
Your two examples use different CompletionFunction types.
std::barrier b{2} uses the default CompletionFunction type, which is an unspecified DefaultConstructible function that does nothing.
std::make_shared<std::barrier<std::function<void()>>> use std::function<void()> as its CompletionFunction type, which while DefaultConstructible, will throw an exception if you attempt to call it without giving it a callable to wrap.
Since you never initialize your std::barrier's CompletionFunction and std::barrier's CompletionFunction isn't allowed to throw exceptions, you get undefined behavior.
(Technically I think it's undefined behavior to use std::function as the CompletionFunction type at all, since std::is_nothrow_invocable_v<std::function<void()>&> is false)
I have created a class with a constructor.
I am creating n number of objects in main.cpp. Now with each object creation, the constructor should be called automatically.
But since I am creating this object in main.cpp, I want to use signals to handle the "Ctrl+C" termination.
I have written the main.cpp like this:
#include <iostream>
#include "Session.hpp"
class Session {
public:
Session(int _count):count(_count) {
std::cout << "Create Session " << count << std::endl;
}
~Session() {
std::cout << "Destroy Session " << count << std::endl;
}
Print() {
cout << "Hello" << endl;
}
private:
const int count;
};
void signal_handler(int signal, unsigned int count, **WHAT SHOULD I WRITE HERE**) {
for (unsigned int del_count = 0; del_count < count; del_count++) {
**I WANT TO DELETE ALL THE FOO OBJECTS CREATED IN THE MAIN FUNCTION**
}
}
int main() {
unsigned int num_of_sessions;
cin >> num_of_sessions;
signal(SIGINT, signal_handler, num_of_sessions, **WHAT MORE SHOULD I PASS HERE**);
unique_ptr<Session> Foo[num_of_sessions];
unsigned int count = 0; // initialize the counter for sessions
while (count < num_of_sessions) {
Foo[count] (new Session(count));
count++;
}
while (true){
for (count = 0; count < num_of_sessions; count++) {
Foo[count]->PrintName();
}
}
return 0;
}
I am getting this error as
error: no match for call to ‘(std::unique_ptr) (Session*)’
Foo[count] (new Session(count));
Any suggestion?
You don't need to delete unique_ptr, they will be destroyed when the variable goes out of scope; in this case it will be the end of the main function.
That's the point of unique_ptr, you don't have to take care of memory management.
If you simply want to set a signal and perform an action on an object allocated in the stack inside the main function you can just use a pointer like this :
#include <iostream>
#include <csignal>
#include <vector>
#include <atomic>
#include <memory>
#include <chrono>
#include <thread>
std::atomic<bool> end_condition;
class Session {
public:
Session(int _count):count(_count) {
std::cout << "Create Session " << count << std::endl;
}
~Session() {
std::cout << "Destroy Session " << count << std::endl;
}
void printSessionCount() {
std::cout << "Session count is " << count << std::endl;
}
private:
const int count;
};
std::vector< std::unique_ptr<Session>>* foo_p; // <= Probably not necessary but this is how you would access your variable defined in main in signal handler
void signal_handler(int signal) {
// You don't have handle clean up of your vector.
// foo_p->clear(); <= Unnecessary to delete every element of your vector here, since they will be automatically deleted at the end of main
end_condition.store(false);
}
int main() {
end_condition.store(true);
unsigned int num_of_sessions;
std::cin >> num_of_sessions;
// register signal SIGINT and signal handler
signal(SIGINT, signal_handler);
std::vector< std::unique_ptr<Session> > foo;
foo_p = &foo; // Make your global pointer points to your pointer created in the main function. Accessing foo_p before the point will result in a segmentation fault since the pointer will be null
// You may not need this at all depending on what you want to do during in the signal handler
for(int i = 0; i < num_of_sessions; ++i) {
// Populate your vector
foo.emplace_back(new Session(i));
}
while (end_condition.load()){
//Call a function for each vector
for(int i =0; i < foo.size(); ++i) {
foo.at(i)->printSessionCount();
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
} // vector foo memory will be deleted here
I am following Boost multithreading tutorial here
. The code is as follow:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
using std::cout;
using std::cin;
using std::endl;
class CallableClass
{
private:
// Number of iterations
int m_iterations;
public:
// Default constructor
CallableClass()
{
m_iterations = 10;
}
// Constructor with number of iterations
CallableClass(int iterations)
{
m_iterations = iterations;
}
// Copy constructor
CallableClass(const CallableClass& source)
{
m_iterations = source.m_iterations;
}
// Destructor
~CallableClass()
{
cout << "Callable class exiting." << endl;
}
// Assignment operator
CallableClass& operator = (const CallableClass& source)
{
m_iterations = source.m_iterations;
return *this;
}
// Static function called by thread
static void StaticFunction()
{
for (int i = 0; i < 10; i++) // Hard-coded upper limit
{
cout << i << " - Do something in parallel (Static function)." << endl;
boost::this_thread::yield(); // 'yield' discussed in section 18.6
}
}
// Operator() called by the thread
void operator () ()
{
for (int i = 0; i < m_iterations; i++)
{
cout << i << " - Do something in parallel (operator() )." << endl;
boost::this_thread::yield(); // 'yield' discussed in section 18.6
}
}
};
int main()
{
boost::thread t(&CallableClass::StaticFunction);
for (int i = 0; i < 10; i++)
cout << i << " - Do something in main method." << endl;
return 0;
}
However, if I change main() to this:
int main()
{
// Using a callable object as thread function
int numberIterations = 20;
CallableClass c(numberIterations);
boost::thread t(c);
for (int i = 0; i < 10; i++)
cout << i << " - Do something in main method." << endl;
return 0;
}
The class destructor is called before the operator is executed. I don't quite understand this behavior. Shouldn't the class stops executing when the destructor is called? Also, why does the operator has two sets of brackets? How do I know when the 2nd thread (not main()) stops and safely exits? Thanks.
No boost::thread doesn't stop executing when it is destructed. std::thread doesn't allow you to do this and will call std::terminate if you destruct the thread without joining it.
You need to add t.join() to the end of your main() method.
void operator () () is the () operator with no parameters, the first () is the name of the operator, the second() is the list of parameters. For example a callable class with parameters would look like:
struct s
{
void operator ()( int p ) {};
}
I have a list of objects, each object has member variables which are calculated by an "update" function. I want to update the objects in parallel, that is I want to create a thread for each object to execute it's update function.
Is this a reasonable thing to do? Any reasons why this may not be a good idea?
Below is a program which attempts to do what I described, this is a complete program so you should be able to run it (I'm using VS2015). The goal is to update each object in parallel. The problem is that once the update function completes, the thread throws an "resource dead lock would occur" exception and aborts.
Where am I going wrong?
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <thread>
#include <mutex>
#include <chrono>
class Object
{
public:
Object(int sleepTime, unsigned int id)
: m_pSleepTime(sleepTime), m_pId(id), m_pValue(0) {}
void update()
{
if (!isLocked()) // if an object is not locked
{
// create a thread to perform it's update
m_pThread.reset(new std::thread(&Object::_update, this));
}
}
unsigned int getId()
{
return m_pId;
}
unsigned int getValue()
{
return m_pValue;
}
bool isLocked()
{
bool mutexStatus = m_pMutex.try_lock();
if (mutexStatus) // if mutex is locked successfully (meaning it was unlocked)
{
m_pMutex.unlock();
return false;
}
else // if mutex is locked
{
return true;
}
}
private:
// private update function which actually does work
void _update()
{
m_pMutex.lock();
{
std::cout << "thread " << m_pId << " sleeping for " << m_pSleepTime << std::endl;
std::chrono::milliseconds duration(m_pSleepTime);
std::this_thread::sleep_for(duration);
m_pValue = m_pId * 10;
}
m_pMutex.unlock();
try
{
m_pThread->join();
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl; // throws "resource dead lock would occur"
}
}
unsigned int m_pSleepTime;
unsigned int m_pId;
unsigned int m_pValue;
std::mutex m_pMutex;
std::shared_ptr<std::thread> m_pThread; // store reference to thread so it doesn't go out of scope when update() returns
};
typedef std::shared_ptr<Object> ObjectPtr;
class ObjectManager
{
public:
ObjectManager()
: m_pNumObjects(0){}
void updateObjects()
{
for (int i = 0; i < m_pNumObjects; ++i)
{
m_pObjects[i]->update();
}
}
void removeObjectByIndex(int index)
{
m_pObjects.erase(m_pObjects.begin() + index);
}
void addObject(ObjectPtr objPtr)
{
m_pObjects.push_back(objPtr);
m_pNumObjects++;
}
ObjectPtr getObjectByIndex(unsigned int index)
{
return m_pObjects[index];
}
private:
std::vector<ObjectPtr> m_pObjects;
int m_pNumObjects;
};
void main()
{
int numObjects = 2;
// Generate sleep time for each object
std::vector<int> objectSleepTimes;
objectSleepTimes.reserve(numObjects);
for (int i = 0; i < numObjects; ++i)
objectSleepTimes.push_back(rand());
ObjectManager mgr;
// Create some objects
for (int i = 0; i < numObjects; ++i)
mgr.addObject(std::make_shared<Object>(objectSleepTimes[i], i));
// Print expected object completion order
// Sort from smallest to largest
std::sort(objectSleepTimes.begin(), objectSleepTimes.end());
for (int i = 0; i < numObjects; ++i)
std::cout << objectSleepTimes[i] << ", ";
std::cout << std::endl;
// Update objects
mgr.updateObjects();
int numCompleted = 0; // number of objects which finished updating
while (numCompleted != numObjects)
{
for (int i = 0; i < numObjects; ++i)
{
auto objectRef = mgr.getObjectByIndex(i);
if (!objectRef->isLocked()) // if object is not locked, it is finished updating
{
std::cout << "Object " << objectRef->getId() << " completed. Value = " << objectRef->getValue() << std::endl;
mgr.removeObjectByIndex(i);
numCompleted++;
}
}
}
system("pause");
}
Looks like you've got a thread that is trying to join itself.
While I was trying to understand your solution I was simplifying it a lot. And I come to point that you use std::thread::join() method in a wrong way.
std::thread provide capabilities to wait for it completion (non-spin wait) -- In your example you wait for thread completion in infinite loop (snip wait) that will consume CPU time heavily.
You should call std::thread::join() from other thread to wait for thread completion. Mutex in Object in your example is not necessary. Moreover, you missed one mutex to synchronize access to std::cout, which is not thread-safe. I hope the example below will help.
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <thread>
#include <mutex>
#include <chrono>
#include <cassert>
// cout is not thread-safe
std::recursive_mutex cout_mutex;
class Object {
public:
Object(int sleepTime, unsigned int id)
: _sleepTime(sleepTime), _id(id), _value(0) {}
void runUpdate() {
if (!_thread.joinable())
_thread = std::thread(&Object::_update, this);
}
void waitForResult() {
_thread.join();
}
unsigned int getId() const { return _id; }
unsigned int getValue() const { return _value; }
private:
void _update() {
{
{
std::lock_guard<std::recursive_mutex> lock(cout_mutex);
std::cout << "thread " << _id << " sleeping for " << _sleepTime << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(_sleepTime));
_value = _id * 10;
}
std::lock_guard<std::recursive_mutex> lock(cout_mutex);
std::cout << "Object " << getId() << " completed. Value = " << getValue() << std::endl;
}
unsigned int _sleepTime;
unsigned int _id;
unsigned int _value;
std::thread _thread;
};
class ObjectManager : public std::vector<std::shared_ptr<Object>> {
public:
void runUpdate() {
for (auto it = this->begin(); it != this->end(); ++it)
(*it)->runUpdate();
}
void waitForAll() {
auto it = this->begin();
while (it != this->end()) {
(*it)->waitForResult();
it = this->erase(it);
}
}
};
int main(int argc, char* argv[]) {
enum {
TEST_OBJECTS_NUM = 2,
};
srand(static_cast<unsigned int>(time(nullptr)));
ObjectManager mgr;
// Generate sleep time for each object
std::vector<int> objectSleepTimes;
objectSleepTimes.reserve(TEST_OBJECTS_NUM);
for (int i = 0; i < TEST_OBJECTS_NUM; ++i)
objectSleepTimes.push_back(rand() * 9 / RAND_MAX + 1); // 1..10 seconds
// Create some objects
for (int i = 0; i < TEST_OBJECTS_NUM; ++i)
mgr.push_back(std::make_shared<Object>(objectSleepTimes[i], i));
assert(mgr.size() == TEST_OBJECTS_NUM);
// Print expected object completion order
// Sort from smallest to largest
std::sort(objectSleepTimes.begin(), objectSleepTimes.end());
for (size_t i = 0; i < mgr.size(); ++i)
std::cout << objectSleepTimes[i] << ", ";
std::cout << std::endl;
// Update objects
mgr.runUpdate();
mgr.waitForAll();
//system("pause"); // use Ctrl+F5 to run the app instead. That's more reliable in case of sudden app exit.
}
About is it a reasonable thing to do...
A better approach is to create an object update queue. Objects that need to be updated are added to this queue, which can be fulfilled by a group of threads instead of one thread per object.
The benefits are:
No 1-to-1 correspondence between thread and objects. Creating a thread is a heavy operation, probably more expensive than most update code for a single object.
Supports thousands of objects: with your solution you would need to create thousands of threads, which you will find exceeds your OS capacity.
Can support additional features like declaring dependencies between objects or updating a group of related objects as one operation.
Consider following example -
#include <boost/thread.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
boost::shared_mutex mutex;
std::vector<int> random_numbers;
void fill()
{
std::srand(static_cast<unsigned int>(std::time(0)));
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::shared_mutex> lock(mutex);
random_numbers.push_back(std::rand());
lock.unlock();
wait(1);
}
}
void print()
{
for (int i = 0; i < 3; ++i)
{
wait(1);
boost::shared_lock<boost::shared_mutex> lock(mutex);
std::cout << random_numbers.back() << std::endl;
}
}
int sum = 0;
void count()
{
for (int i = 0; i < 3; ++i)
{
wait(1);
boost::shared_lock<boost::shared_mutex> lock(mutex);
sum += random_numbers.back();
}
}
int main()
{
boost::thread t1(fill);
boost::thread t2(print);
boost::thread t3(count);
t1.join();
t2.join();
t3.join();
std::cout << "Summe: " << sum << std::endl;
}
In the given example, both print() and count() access random_numbers read-only. While the print() function writes the last number of random_numbers to the standard output stream, the count() function adds it to the variable sum. Since neither function modifies random_numbers, both can access it at the same time using a non-exclusive lock of type boost::shared_lock.
My question is : As the resource is read only why the shared mutex is needed at the first place in count and print function?' Cant we manage without it?
As the resource is read only [...]
No, it is not : the fill() method proceed to writes through the following :
random_numbers.push_back(std::rand()); // write to random_numbers
So the shared mutex really is necessary to synchronize your access to the vector.