While using ThreadSanitizer to check Duke's implementation I stumbled upon this data race.
WARNING: ThreadSanitizer: data race (pid=17556)
Atomic write of size 4 at 0x7ff153d4cdc0 by thread T2:
#0 __tsan_atomic32_exchange ??:0 (exe+0x0000001376a7)
#1 OpenImageIO::v1_3::spin_mutex::try_lock() /home/clitte/git/oiio/src/include/thread.h:570 (libOpenImageIO.so.1.3+0x0000003d482a)
#2 OpenImageIO::v1_3::spin_mutex::lock() /home/clitte/git/oiio/src/include/thread.h:534 (libOpenImageIO.so.1.3+0x0000003d4731)
#3 OpenImageIO::v1_3::spin_rw_mutex::read_lock() /home/clitte/git/oiio/src/include/thread.h:633 (libOpenImageIO.so.1.3+0x000000b62ff7)
#4 read_lock_guard /home/clitte/git/oiio/src/include/thread.h:669 (libOpenImageIO.so.1.3+0x000000b62f96)
#5 read_lock_guard /home/clitte/git/oiio/src/include/thread.h:669 (libOpenImageIO.so.1.3+0x000000b58430)
#6 OpenImageIO::v1_3::ustring::make_unique(char const*) /home/clitte/git/oiio/src/libutil/ustring.cpp:179 (libOpenImageIO.so.1.3+0x000000b56457)
#7 ustring /home/clitte/git/oiio/src/include/ustring.h:166 (libOpenImageIO.so.1.3+0x000000306ea6)
#8 ustring /home/clitte/git/oiio/src/include/ustring.h:167 (libOpenImageIO.so.1.3+0x000000306e10)
#9 ustring /home/clitte/git/oiio/src/include/ustring.h:186 (libOpenImageIO.so.1.3+0x000000306c67)
#10 ustring /home/clitte/git/oiio/src/include/ustring.h:186 (libOpenImageIO.so.1.3+0x000000306bd0)
#11 OpenImageIO::v1_3::ParamValue::init(std::string, OpenImageIO::v1_3::TypeDesc, int, void const*, bool) /home/clitte/git/oiio/src/include/paramlist.h:104 (libOpenImageIO.so.1.3+0x0000002e8399)
#12 OpenImageIO::v1_3::ImageSpec::attribute(std::string const&, OpenImageIO::v1_3::TypeDesc, void const*) /home/clitte/git/oiio/src/libOpenImageIO/formatspec.cpp:355 (libOpenImageIO.so.1.3+0x0000002d962f)
#13 OpenImageIO::v1_3::ImageSpec::attribute(std::string const&, char const*) /home/clitte/git/oiio/src/include/imageio.h:306 (libOpenImageIO.so.1.3+0x0000002c2643)
#14 OpenImageIO::v1_3::JpgInput::open(std::string const&, OpenImageIO::v1_3::ImageSpec&) /home/clitte/git/oiio/src/jpeg.imageio/jpeginput.cpp:212 (libOpenImageIO.so.1.3+0x000000d76af6)
#15 OpenImageIOReader /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:135 (exe+0x0000001603b6)
#16 OpenImageIOReader /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:175 (exe+0x00000015fee0)
#17 duke::OpenImageIODescriptor::getReaderFromFile(char const*) const /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:223 (exe+0x00000015fdba)
#18 duke::(anonymous namespace)::tryReader(char const*, duke::IIODescriptor const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:45 (exe+0x0000002e7f80)
#19 duke::(anonymous namespace)::load(char const*, char const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:55 (exe+0x0000002e6d71)
#20 duke::load(char const*, char const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&, std::string&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:66 (exe+0x0000002e69a3)
#21 duke::LoadedImageCache::workerStep(std::pair<duke::IMediaStream const*, unsigned long>&, std::string&, std::string&) /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:142 (exe+0x00000024d04c)
#22 duke::LoadedImageCache::workerFunction() /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:109 (exe+0x00000024c82f)
#23 void std::_Mem_fn<void (duke::LoadedImageCache::*)()>::operator()<, void>(duke::LoadedImageCache*) const /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:601 (exe+0x00000026ca43)
#24 void std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1732 (exe+0x00000026c8d0)
#25 std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)>::operator()() /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1720 (exe+0x00000026c840)
#26 std::thread::_Impl<std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)> >::_M_run() /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:115 (exe+0x00000026c7e9)
#27 <null> <null>:0 (libstdc++.so.6+0x0000000b1d2f)
Previous write of size 4 at 0x7ff153d4cdc0 by thread T1:
#0 OpenImageIO::v1_3::spin_mutex::unlock() /home/clitte/git/oiio/src/include/thread.h:553 (libOpenImageIO.so.1.3+0x0000003d4618)
#1 OpenImageIO::v1_3::spin_rw_mutex::read_lock() /home/clitte/git/oiio/src/include/thread.h:637 (libOpenImageIO.so.1.3+0x000000b63015)
#2 read_lock_guard /home/clitte/git/oiio/src/include/thread.h:669 (libOpenImageIO.so.1.3+0x000000b62f96)
#3 read_lock_guard /home/clitte/git/oiio/src/include/thread.h:669 (libOpenImageIO.so.1.3+0x000000b58430)
#4 OpenImageIO::v1_3::ustring::make_unique(char const*) /home/clitte/git/oiio/src/libutil/ustring.cpp:179 (libOpenImageIO.so.1.3+0x000000b56457)
#5 ustring /home/clitte/git/oiio/src/include/ustring.h:166 (libOpenImageIO.so.1.3+0x000000306ea6)
#6 ustring /home/clitte/git/oiio/src/include/ustring.h:167 (libOpenImageIO.so.1.3+0x000000306e10)
#7 ustring /home/clitte/git/oiio/src/include/ustring.h:186 (libOpenImageIO.so.1.3+0x000000306c67)
#8 ustring /home/clitte/git/oiio/src/include/ustring.h:186 (libOpenImageIO.so.1.3+0x000000306bd0)
#9 OpenImageIO::v1_3::ParamValue::init(std::string, OpenImageIO::v1_3::TypeDesc, int, void const*, bool) /home/clitte/git/oiio/src/include/paramlist.h:104 (libOpenImageIO.so.1.3+0x0000002e8399)
#10 OpenImageIO::v1_3::ImageSpec::attribute(std::string const&, OpenImageIO::v1_3::TypeDesc, void const*) /home/clitte/git/oiio/src/libOpenImageIO/formatspec.cpp:355 (libOpenImageIO.so.1.3+0x0000002d962f)
#11 OpenImageIO::v1_3::ImageSpec::attribute(std::string const&, char const*) /home/clitte/git/oiio/src/include/imageio.h:306 (libOpenImageIO.so.1.3+0x0000002c2643)
#12 OpenImageIO::v1_3::JpgInput::open(std::string const&, OpenImageIO::v1_3::ImageSpec&) /home/clitte/git/oiio/src/jpeg.imageio/jpeginput.cpp:212 (libOpenImageIO.so.1.3+0x000000d76af6)
#13 OpenImageIOReader /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:135 (exe+0x0000001603b6)
#14 OpenImageIOReader /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:175 (exe+0x00000015fee0)
#15 duke::OpenImageIODescriptor::getReaderFromFile(char const*) const /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:223 (exe+0x00000015fdba)
#16 duke::(anonymous namespace)::tryReader(char const*, duke::IIODescriptor const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:45 (exe+0x0000002e7f80)
#17 duke::(anonymous namespace)::load(char const*, char const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:55 (exe+0x0000002e6d71)
#18 duke::load(char const*, char const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&, std::string&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:66 (exe+0x0000002e69a3)
#19 duke::LoadedImageCache::workerStep(std::pair<duke::IMediaStream const*, unsigned long>&, std::string&, std::string&) /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:142 (exe+0x00000024d04c)
#20 duke::LoadedImageCache::workerFunction() /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:109 (exe+0x00000024c82f)
#21 void std::_Mem_fn<void (duke::LoadedImageCache::*)()>::operator()<, void>(duke::LoadedImageCache*) const /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:601 (exe+0x00000026ca43)
#22 void std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1732 (exe+0x00000026c8d0)
#23 std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)>::operator()() /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1720 (exe+0x00000026c840)
#24 std::thread::_Impl<std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)> >::_M_run() /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:115 (exe+0x00000026c7e9)
#25 <null> <null>:0 (libstdc++.so.6+0x0000000b1d2f)
Thread T2 (tid=17560, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x000000123772)
#1 <null> <null>:0 (libstdc++.so.6+0x0000000b1f7e)
#2 std::thread::thread<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:138 (exe+0x000000268ab0)
#3 void __gnu_cxx::new_allocator<std::thread>::construct<std::thread, void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(std::thread*, void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/ext/new_allocator.h:120 (exe+0x0000002689f5)
#4 _ZNSt16allocator_traitsISaISt6threadEE12_S_constructIS0_JMN4duke16LoadedImageCacheEFvvEPS5_EEENSt9enable_ifIXsr18__construct_helperIT_DpT0_EE5valueEvE4typeERS1_PSA_DpOSB_ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/alloc_traits.h:254 (exe+0x0000002688fd)
#5 _ZNSt16allocator_traitsISaISt6threadEE9constructIS0_JMN4duke16LoadedImageCacheEFvvEPS5_EEEDTcl12_S_constructfp_fp0_spclsr3stdE7forwardIT0_Efp1_EEERS1_PT_DpOS9_ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/alloc_traits.h:393 (exe+0x000000266acd)
#6 void std::vector<std::thread, std::allocator<std::thread> >::_M_emplace_back_aux<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/vector.tcc:409 (exe+0x000000266d0e)
#7 void std::vector<std::thread, std::allocator<std::thread> >::emplace_back<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/vector.tcc:101 (exe+0x00000024f497)
#8 duke::LoadedImageCache::startWorkers() /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:93 (exe+0x00000024ba46)
#9 duke::LoadedImageCache::load(duke::Timeline const&) /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:32 (exe+0x00000024bbbb)
#10 duke::LoadedTextureCache::load(duke::Timeline const&) /home/clitte/git/duke/src/duke/engine/cache/LoadedTextureCache.cpp:20 (exe+0x00000020d995)
#11 duke::Player::load(duke::Timeline const&, FrameDuration const&) /home/clitte/git/duke/src/duke/engine/Player.cpp:11 (exe+0x000000277019)
#12 duke::DukeMainWindow::load(duke::Timeline const&, FrameDuration const&, duke::FitMode, int) /home/clitte/git/duke/src/duke/engine/DukeMainWindow.cpp:64 (exe+0x0000001e9269)
#13 DukeApplication /home/clitte/git/duke/src/duke/engine/DukeApplication.cpp:136 (exe+0x0000001be2ef)
#14 main /home/clitte/git/duke/src/duke/main.cpp:37 (exe+0x000000168d34)
Thread T1 (tid=17559, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x000000123772)
#1 <null> <null>:0 (libstdc++.so.6+0x0000000b1f7e)
#2 std::thread::thread<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:138 (exe+0x000000268ab0)
#3 void __gnu_cxx::new_allocator<std::thread>::construct<std::thread, void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(std::thread*, void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/ext/new_allocator.h:120 (exe+0x0000002689f5)
#4 _ZNSt16allocator_traitsISaISt6threadEE12_S_constructIS0_JMN4duke16LoadedImageCacheEFvvEPS5_EEENSt9enable_ifIXsr18__construct_helperIT_DpT0_EE5valueEvE4typeERS1_PSA_DpOSB_ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/alloc_traits.h:254 (exe+0x0000002688fd)
#5 _ZNSt16allocator_traitsISaISt6threadEE9constructIS0_JMN4duke16LoadedImageCacheEFvvEPS5_EEEDTcl12_S_constructfp_fp0_spclsr3stdE7forwardIT0_Efp1_EEERS1_PT_DpOS9_ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/alloc_traits.h:393 (exe+0x000000266acd)
#6 void std::vector<std::thread, std::allocator<std::thread> >::_M_emplace_back_aux<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/vector.tcc:409 (exe+0x000000266d0e)
#7 void std::vector<std::thread, std::allocator<std::thread> >::emplace_back<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/vector.tcc:101 (exe+0x00000024f497)
#8 duke::LoadedImageCache::startWorkers() /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:93 (exe+0x00000024ba46)
#9 duke::LoadedImageCache::load(duke::Timeline const&) /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:32 (exe+0x00000024bbbb)
#10 duke::LoadedTextureCache::load(duke::Timeline const&) /home/clitte/git/duke/src/duke/engine/cache/LoadedTextureCache.cpp:20 (exe+0x00000020d995)
#11 duke::Player::load(duke::Timeline const&, FrameDuration const&) /home/clitte/git/duke/src/duke/engine/Player.cpp:11 (exe+0x000000277019)
#12 duke::DukeMainWindow::load(duke::Timeline const&, FrameDuration const&, duke::FitMode, int) /home/clitte/git/duke/src/duke/engine/DukeMainWindow.cpp:64 (exe+0x0000001e9269)
#13 DukeApplication /home/clitte/git/duke/src/duke/engine/DukeApplication.cpp:136 (exe+0x0000001be2ef)
#14 main /home/clitte/git/duke/src/duke/main.cpp:37 (exe+0x000000168d34)
SUMMARY: ThreadSanitizer: data race ??:0 __tsan_atomic32_exchange