I trying to understand lock-free programming, and wrote a lock-free stack:
template <typename T>
class LockFreeStack
{
struct Node
{
std::shared_ptr<T> data;
Node* next;
explicit Node(const T& _data)
: data(std::make_shared<T>(_data)), next(nullptr)
{}
};
std::atomic<Node*> head;
public:
void push(const T& data)
{
auto n{new Node(data)};
n->next = head.load();
while (!head.compare_exchange_weak(n->next, n))
;
}
std::shared_ptr<T> pop(void)
{
auto old_head{head.load()};
while (old_head && head.compare_exchange_weak(old_head, old_head->next))
;
return old_head ? old_head->data : std::shared_ptr<T>{};
}
};
And two thread for push/pop operation on:
static LockFreeStack<int> global_stack;
And main
function:
int main(void)
{
std::srand(std::time(nullptr));
std::thread pushing_thread([](void) {
for (size_t i{}; i < MAX_LENGTH; ++i)
{
const auto v{std::rand() % 10000};
global_stack.push(v);
std::cout << "\e[41mPoping: " << v << "\e[m" << std::endl;
}
});
std::thread poping_thread([](void) {
for (size_t i{}; i < MAX_LENGTH; ++i)
{
if (auto v{global_stack.pop()}; v)
{
std::cout << "\e[42mPushing: " << *v << "\e[m" << std::endl;
}
}
});
pushing_thread.join();
poping_thread.join();
}
This program only run pushing_thread
in Debug mode, but when i run the program with debugger it run both thread as expected or if i wait a moment between the threads:
std::thread pushing_thread(...);
std::this_thread::sleep_for(1s);
std::thread poping_thread(...);
It works properly. So what is happens when we run the program with debugger ?
- Compiler:
GCC 9.3
. - Compiler flags:
-std=c++2a -lpthread -Wall
. - OS:
ArchLinux with linux-5.5.13
.