Atomic Shared Pointer (std::atomic<std::shared_ptr<>
)¶
Safe: Control Block Modification¶
#include <iostream>
#include <memory>
#include <thread>
int main()
{
auto p = std::make_shared<int>(42);
auto threadfunc = [p](){ // <-- copy
while (true)
auto local_p = p; // <-- copy
};
std::thread t1(threadfunc);
std::thread t2(threadfunc);
t1.join();
t2.join();
return 0;
}
Sideways: Synchronizing With Thread Startup (1)¶
A note on
use_count()
: threads may not even running yet⟶
use_count()
is nothing to build uponSynchronization/communication needed
⟶ std::promise and std::future (And Some std::chrono) (Some Live Hacking)
#include <iostream>
#include <memory>
#include <thread>
int main()
{
auto p = std::make_shared<int>(42);
auto threadfunc = [p](){
while (true)
auto local_p = p;
};
std::thread t1(threadfunc);
std::thread t2(threadfunc);
std::cout << p.use_count() << std::endl; // <-- moving target but safe
t1.join();
t2.join();
return 0;
}
Sideways: Synchronizing With Thread Startup (2)¶
#include <iostream>
#include <memory>
#include <thread>
#include <future>
int main()
{
std::promise<void> started_promise;
auto started_future = started_promise.get_future();
auto p = std::make_shared<int>(42);
auto threadfunc = [p, &started_promise](){
started_promise.set_value(); // <-- kick waiter loose
while (true)
auto local_p = p;
};
std::thread t(threadfunc);
started_future.get(); // <-- wait until kicked
std::cout << p.use_count() << std::endl;
t.join();
return 0;
}
Unsafe: Assignment To Shared Pointer¶
#include <memory>
#include <thread>
int main()
{
auto p = std::make_shared<int>(42);
auto threadfunc = [&p](){
while (true)
p = std::make_shared<int>(666); // <-- **NOT** threadsafe!
};
std::thread t1(threadfunc);
std::thread t2(threadfunc);
t1.join();
t2.join();
return 0;
}
Solution: std::atomic_store<>
Specialization¶
Deprecated in C++20
#include <memory>
#include <thread>
int main()
{
auto p = std::make_shared<int>(42);
auto threadfunc = [&p](){
while (true)
std::atomic_store(&p, std::make_shared<int>(666)); // <-- ugly
};
std::thread t1(threadfunc);
std::thread t2(threadfunc);
t1.join();
t2.join();
return 0;
}
Solution: std::atomic<std::shared_ptr>
¶
Don’t want manually enable thread safety by using global function
Better: want the object itself to be thread safe
Drawback: no
std::make_atomic_shared()
#include <memory>
#include <thread>
int main()
{
std::atomic<std::shared_ptr<int>> p = std::make_shared<int>(42);
auto threadfunc = [&p](){
while (true)
p = std::make_shared<int>(666);
};
std::thread t1(threadfunc);
std::thread t2(threadfunc);
t1.join();
t2.join();
return 0;
}