Skip to content

Instantly share code, notes, and snippets.

@vittorioromeo
Last active May 20, 2016 20:24
Show Gist options
  • Save vittorioromeo/8c32d9f6c9bcc6389e2dc203ec415f32 to your computer and use it in GitHub Desktop.
Save vittorioromeo/8c32d9f6c9bcc6389e2dc203ec415f32 to your computer and use it in GitHub Desktop.
#include <array>
#include <atomic>
#include "./blockingconcurrentqueue.h"
using namespace std::chrono_literals;
// global counter
// * the program can exit when it reaches 1000
// * incremented by tasks
std::atomic<int> ctr{0};
// task
// * non-copyable
// * increments `ctr` on construction
// * transfers some mock state `x` on moves
struct task
{
int x = 0;
task()
{
++ctr;
}
task(const task&) = delete;
task& operator=(const task&) = delete;
task(task&& rhs) : x{rhs.x}
{
}
task& operator=(task&& rhs)
{
x = rhs.x;
return *this;
}
};
// task queue
moodycamel::BlockingConcurrentQueue<task> q;
// worker
// * contains thread that constantly calls `wait_dequeue`
// * on dtor, spawns tasks until thread is joined
struct worker
{
std::thread th;
std::atomic<bool> running{true};
std::atomic<bool> exited{false};
worker()
{
th = std::thread([this]
{
task t;
while(running)
{
q.wait_dequeue(t);
}
exited = true;
});
}
~worker()
{
running = false;
while(!exited)
{
q.enqueue(task{});
std::this_thread::sleep_for(1ms);
}
th.join();
}
};
int main()
{
// create 8 workers
std::array<worker, 8> ws;
// enqueue 1000 tasks
for(int i = 0; i < 1000; ++i)
{
q.enqueue(task{});
}
// wait for `ctr` to be `>= 1000`
while(ctr < 1000)
{
std::this_thread::sleep_for(1ms);
}
}
WARNING: ThreadSanitizer: data race (pid=15381)
Read of size 4 at 0x7d340000cf48 by thread T7:
#0 task::operator=(task&&) <null> (a.out+0x000000402c36)
#1 bool moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::ImplicitProducer::dequeue<task>(task&) <null> (a.out+0x000000406279)
#2 bool moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::ProducerBase::dequeue<task>(task&) <null> (a.out+0x000000405340)
#3 bool moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::try_dequeue<task>(task&) <null> (a.out+0x0000004044e9)
#4 void moodycamel::BlockingConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::wait_dequeue<task>(task&) <null> (a.out+0x000000403303)
#5 worker::worker()::{lambda()#1}::operator()() const <null> (a.out+0x000000402ce6)
#6 void std::_Bind_simple<worker::worker()::{lambda()#1} ()>::_M_invoke<>(std::_Index_tuple<>) <null> (a.out+0x00000040a1a4)
#7 std::_Bind_simple<worker::worker()::{lambda()#1} ()>::operator()() <null> (a.out+0x00000040a0dd)
#8 std::thread::_State_impl<std::_Bind_simple<worker::worker()::{lambda()#1} ()> >::_M_run() <null> (a.out+0x00000040a018)
#9 execute_native_thread_routine /build/gcc-multilib/src/gcc/libstdc++-v3/src/c++11/thread.cc:83 (libstdc++.so.6+0x0000000baaae)
Previous write of size 8 at 0x7d340000cf48 by main thread:
#0 malloc /build/gcc-multilib/src/gcc/libsanitizer/tsan/tsan_interceptors.cc:538 (libtsan.so.0+0x000000026aac)
#1 moodycamel::ConcurrentQueueDefaultTraits::malloc(unsigned long) <null> (a.out+0x000000402102)
#2 moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::Block* moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::create<moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::Block>() <null> (a.out+0x00000040880b)
#3 moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::Block* moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::requisition_block<(moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::AllocationMode)0>() <null> (a.out+0x000000407add)
#4 bool moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::ImplicitProducer::enqueue<(moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::AllocationMode)0, task>(task&&) <null> (a.out+0x000000406ed4)
#5 bool moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::inner_enqueue<(moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::AllocationMode)0, task>(task&&) <null> (a.out+0x0000004057eb)
#6 moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::enqueue(task&&) <null> (a.out+0x0000004049c6)
#7 moodycamel::BlockingConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::enqueue(task&&) <null> (a.out+0x00000040343e)
#8 main <null> (a.out+0x0000004016dd)
Location is heap block of size 208 at 0x7d340000cf30 allocated by main thread:
#0 malloc /build/gcc-multilib/src/gcc/libsanitizer/tsan/tsan_interceptors.cc:538 (libtsan.so.0+0x000000026aac)
#1 moodycamel::ConcurrentQueueDefaultTraits::malloc(unsigned long) <null> (a.out+0x000000402102)
#2 moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::Block* moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::create<moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::Block>() <null> (a.out+0x00000040880b)
#3 moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::Block* moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::requisition_block<(moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::AllocationMode)0>() <null> (a.out+0x000000407add)
#4 bool moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::ImplicitProducer::enqueue<(moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::AllocationMode)0, task>(task&&) <null> (a.out+0x000000406ed4)
#5 bool moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::inner_enqueue<(moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::AllocationMode)0, task>(task&&) <null> (a.out+0x0000004057eb)
#6 moodycamel::ConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::enqueue(task&&) <null> (a.out+0x0000004049c6)
#7 moodycamel::BlockingConcurrentQueue<task, moodycamel::ConcurrentQueueDefaultTraits>::enqueue(task&&) <null> (a.out+0x00000040343e)
#8 main <null> (a.out+0x0000004016dd)
Thread T7 (tid=15389, running) created by main thread at:
#0 pthread_create /build/gcc-multilib/src/gcc/libsanitizer/tsan/tsan_interceptors.cc:876 (libtsan.so.0+0x000000028360)
#1 __gthread_create /build/gcc-multilib/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:662 (libstdc++.so.6+0x0000000badc4)
#2 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /build/gcc-multilib/src/gcc/libstdc++-v3/src/c++11/thread.cc:163 (libstdc++.so.6+0x0000000badc4)
#3 worker::worker() <null> (a.out+0x000000402da3)
#4 std::array<worker, 8ul>::array() <null> (a.out+0x000000402f80)
#5 main <null> (a.out+0x0000004016b0)
SUMMARY: ThreadSanitizer: data race (a.out+0x402c36) in task::operator=(task&&)
==================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment