GUI Hello World app contains threading errors

I have followed the tutorial for creating the GUI Hello World application.

I am on Ubuntu 22.04.1 LTS running X11.

I am following:

To check for threading issues.

This basically only involves adding " -fsanitize=thread" option to both the JUCE_CXXFLAGS and JUCE_LDFLAGS.

I am on JUCE v6.1.5 - I think this comes with Ubuntu.

The application starts up as expected and displays “Hello World” but the following errors are reported to the console:

type or paste code here
JUCE v6.1.5
==================
WARNING: ThreadSanitizer: double lock of a mutex (pid=25995)
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749 (NewProject+0x2d3971)
    #2 std::mutex::lock() /usr/include/c++/11/bits/std_mutex.h:100 (NewProject+0x2d39fa)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) <null> (NewProject+0x305e92)
    #4 juce::WaitableEvent::signal() const /usr/share/juce/modules/juce_core/threads/juce_WaitableEvent.cpp:59 (NewProject+0x2c4438)
    #5 juce::Timer::TimerThread::callTimers() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:123 (NewProject+0x39543b)
    #6 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:180 (NewProject+0x395729)
    #7 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /usr/share/juce/modules/juce_events/native/juce_linux_Messaging.cpp:42 (NewProject+0x3983c5)
    #8 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/11/bits/invoke.h:61 (NewProject+0x3b449f)
    #9 std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int> >::value, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/11/bits/invoke.h:154 (NewProject+0x3af8ba)
    #10 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/11/bits/std_function.h:290 (NewProject+0x3a7bb2)
    #11 std::function<void (int)>::operator()(int) const /usr/include/c++/11/bits/std_function.h:590 (NewProject+0x3a1361)
    #12 juce::InternalRunLoop::dispatchPendingEvents() <null> (NewProject+0x3995ad)
    #13 juce::dispatchNextMessageOnSystemQueue(bool) /usr/share/juce/modules/juce_events/native/juce_linux_Messaging.cpp:299 (NewProject+0x3914e3)
    #14 juce::MessageManager::runDispatchLoop() /usr/share/juce/modules/juce_events/messages/juce_MessageManager.cpp:107 (NewProject+0x389ddb)
    #15 juce::JUCEApplicationBase::main() /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (NewProject+0x388eb4)
    #16 juce::JUCEApplicationBase::main(int, char const**) /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (NewProject+0x388d0e)
    #17 main ../../Source/Main.cpp:106 (NewProject+0x987a8)

  Location is heap block of size 544 at 0x7b5400000500 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.0+0x8f162)
    #1 juce::Timer::TimerThread::add(juce::Timer*) /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:142 (NewProject+0x395567)
    #2 juce::Timer::startTimer(int) /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:343 (NewProject+0x38c7aa)
    #3 juce::TopLevelWindowManager::checkFocusAsync() /usr/share/juce/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp:41 (NewProject+0x62e0ac)
    #4 juce::TopLevelWindowManager::addWindow(juce::TopLevelWindow*) /usr/share/juce/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp:65 (NewProject+0x62e227)
    #5 juce::TopLevelWindow::TopLevelWindow(juce::String const&, bool) /usr/share/juce/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp:148 (NewProject+0x5777eb)
    #6 juce::ResizableWindow::ResizableWindow(juce::String const&, juce::Colour, bool) /usr/share/juce/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp:36 (NewProject+0x57238f)
    #7 juce::DocumentWindow::DocumentWindow(juce::String const&, juce::Colour, int, bool) /usr/share/juce/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp:57 (NewProject+0x570173)
    #8 NewProjectApplication::MainWindow::MainWindow(juce::String) <null> (NewProject+0x9981c)
    #9 NewProjectApplication::initialise(juce::String const&) <null> (NewProject+0x996aa)
    #10 juce::JUCEApplicationBase::initialiseApp() /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (NewProject+0x38904b)
    #11 juce::JUCEApplication::initialiseApp() /usr/share/juce/modules/juce_gui_basics/application/juce_Application.cpp:92 (NewProject+0x57d2de)
    #12 juce::JUCEApplicationBase::main() /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (NewProject+0x388e88)
    #13 juce::JUCEApplicationBase::main(int, char const**) /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (NewProject+0x388d0e)
    #14 main ../../Source/Main.cpp:106 (NewProject+0x987a8)

  Mutex M735 (0x7b54000006b8) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749 (NewProject+0x2d3971)
    #2 std::mutex::lock() /usr/include/c++/11/bits/std_mutex.h:100 (NewProject+0x2d39fa)
    #3 std::unique_lock<std::mutex>::lock() <null> (NewProject+0x330675)
    #4 std::unique_lock<std::mutex>::unique_lock(std::mutex&) /usr/include/c++/11/bits/unique_lock.h:69 (NewProject+0x31d16c)
    #5 juce::WaitableEvent::wait(int) const /usr/share/juce/modules/juce_core/threads/juce_WaitableEvent.cpp:33 (NewProject+0x2c42e1)
    #6 juce::Timer::TimerThread::run() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:66 (NewProject+0x3951d5)
    #7 juce::Thread::threadEntryPoint() /usr/share/juce/modules/juce_core/threads/juce_Thread.cpp:96 (NewProject+0x29f5b5)
    #8 juce::juce_threadEntryPoint(void*) /usr/share/juce/modules/juce_core/threads/juce_Thread.cpp:118 (NewProject+0x29f6f5)
    #9 threadEntryProc /usr/share/juce/modules/juce_core/native/juce_posix_SharedCode.h:859 (NewProject+0x2bec72)

SUMMARY: ThreadSanitizer: double lock of a mutex /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749 in __gthread_mutex_lock
==================
==================
WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) (pid=25995)
  Cycle in lock order graph: M735 (0x7b54000006b8) => M76 (0x563ae9cf7960) => M735

  Mutex M76 acquired here while holding mutex M735 in thread T1:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
    #1 juce::CriticalSection::enter() const /usr/share/juce/modules/juce_core/native/juce_posix_SharedCode.h:39 (NewProject+0x2bba1b)
    #2 juce::GenericScopedLock<juce::CriticalSection>::GenericScopedLock(juce::CriticalSection const&) /usr/share/juce/modules/juce_core/threads/juce_ScopedLock.h:67 (NewProject+0xf2e5e)
    #3 juce::Timer::TimerThread::getTimeUntilFirstTimer(int) /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:292 (NewProject+0x396110)
    #4 juce::Timer::TimerThread::run() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:62 (NewProject+0x3951b5)
    #5 juce::Thread::threadEntryPoint() /usr/share/juce/modules/juce_core/threads/juce_Thread.cpp:96 (NewProject+0x29f5b5)
    #6 juce::juce_threadEntryPoint(void*) /usr/share/juce/modules/juce_core/threads/juce_Thread.cpp:118 (NewProject+0x29f6f5)
    #7 threadEntryProc /usr/share/juce/modules/juce_core/native/juce_posix_SharedCode.h:859 (NewProject+0x2bec72)

  Mutex M735 previously acquired by the same thread here:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749 (NewProject+0x2d3971)
    #2 std::mutex::lock() /usr/include/c++/11/bits/std_mutex.h:100 (NewProject+0x2d39fa)
    #3 std::unique_lock<std::mutex>::lock() <null> (NewProject+0x330675)
    #4 std::unique_lock<std::mutex>::unique_lock(std::mutex&) /usr/include/c++/11/bits/unique_lock.h:69 (NewProject+0x31d16c)
    #5 juce::WaitableEvent::wait(int) const /usr/share/juce/modules/juce_core/threads/juce_WaitableEvent.cpp:33 (NewProject+0x2c42e1)
    #6 juce::Timer::TimerThread::run() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:74 (NewProject+0x395204)
    #7 juce::Thread::threadEntryPoint() /usr/share/juce/modules/juce_core/threads/juce_Thread.cpp:96 (NewProject+0x29f5b5)
    #8 juce::juce_threadEntryPoint(void*) /usr/share/juce/modules/juce_core/threads/juce_Thread.cpp:118 (NewProject+0x29f6f5)
    #9 threadEntryProc /usr/share/juce/modules/juce_core/native/juce_posix_SharedCode.h:859 (NewProject+0x2bec72)

  Mutex M735 acquired here while holding mutex M76 in main thread:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749 (NewProject+0x2d3971)
    #2 std::mutex::lock() /usr/include/c++/11/bits/std_mutex.h:100 (NewProject+0x2d39fa)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) <null> (NewProject+0x305e92)
    #4 juce::WaitableEvent::signal() const /usr/share/juce/modules/juce_core/threads/juce_WaitableEvent.cpp:59 (NewProject+0x2c4438)
    #5 juce::Timer::TimerThread::callTimers() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:123 (NewProject+0x39543b)
    #6 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:180 (NewProject+0x395729)
    #7 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /usr/share/juce/modules/juce_events/native/juce_linux_Messaging.cpp:42 (NewProject+0x3983c5)
    #8 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/11/bits/invoke.h:61 (NewProject+0x3b449f)
    #9 std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int> >::value, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/11/bits/invoke.h:154 (NewProject+0x3af8ba)
    #10 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/11/bits/std_function.h:290 (NewProject+0x3a7bb2)
    #11 std::function<void (int)>::operator()(int) const /usr/include/c++/11/bits/std_function.h:590 (NewProject+0x3a1361)
    #12 juce::InternalRunLoop::dispatchPendingEvents() <null> (NewProject+0x3995ad)
    #13 juce::dispatchNextMessageOnSystemQueue(bool) /usr/share/juce/modules/juce_events/native/juce_linux_Messaging.cpp:299 (NewProject+0x3914e3)
    #14 juce::MessageManager::runDispatchLoop() /usr/share/juce/modules/juce_events/messages/juce_MessageManager.cpp:107 (NewProject+0x389ddb)
    #15 juce::JUCEApplicationBase::main() /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (NewProject+0x388eb4)
    #16 juce::JUCEApplicationBase::main(int, char const**) /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (NewProject+0x388d0e)
    #17 main ../../Source/Main.cpp:106 (NewProject+0x987a8)

  Mutex M76 previously acquired by the same thread here:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
    #1 juce::CriticalSection::enter() const /usr/share/juce/modules/juce_core/native/juce_posix_SharedCode.h:39 (NewProject+0x2bba1b)
    #2 juce::GenericScopedUnlock<juce::CriticalSection>::~GenericScopedUnlock() /usr/share/juce/modules/juce_core/threads/juce_ScopedLock.h:148 (NewProject+0xf82b2)
    #3 juce::Timer::TimerThread::callTimers() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:121 (NewProject+0x395404)
    #4 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:180 (NewProject+0x395729)
    #5 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /usr/share/juce/modules/juce_events/native/juce_linux_Messaging.cpp:42 (NewProject+0x3983c5)
    #6 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/11/bits/invoke.h:61 (NewProject+0x3b449f)
    #7 std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int> >::value, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/11/bits/invoke.h:154 (NewProject+0x3af8ba)
    #8 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/11/bits/std_function.h:290 (NewProject+0x3a7bb2)
    #9 std::function<void (int)>::operator()(int) const /usr/include/c++/11/bits/std_function.h:590 (NewProject+0x3a1361)
    #10 juce::InternalRunLoop::dispatchPendingEvents() <null> (NewProject+0x3995ad)
    #11 juce::dispatchNextMessageOnSystemQueue(bool) /usr/share/juce/modules/juce_events/native/juce_linux_Messaging.cpp:299 (NewProject+0x3914e3)
    #12 juce::MessageManager::runDispatchLoop() /usr/share/juce/modules/juce_events/messages/juce_MessageManager.cpp:107 (NewProject+0x389ddb)
    #13 juce::JUCEApplicationBase::main() /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (NewProject+0x388eb4)
    #14 juce::JUCEApplicationBase::main(int, char const**) /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (NewProject+0x388d0e)
    #15 main ../../Source/Main.cpp:106 (NewProject+0x987a8)

  Thread T1 (tid=26002, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 juce::Thread::launchThread() /usr/share/juce/modules/juce_core/native/juce_posix_SharedCode.h:913 (NewProject+0x2bed62)
    #2 juce::Thread::startThread() /usr/share/juce/modules/juce_core/threads/juce_Thread.cpp:130 (NewProject+0x29f799)
    #3 juce::Thread::startThread(int) /usr/share/juce/modules/juce_core/threads/juce_Thread.cpp:147 (NewProject+0x29f8c3)
    #4 juce::Timer::TimerThread::handleAsyncUpdate() /usr/share/juce/modules/juce_events/timers/juce_Timer.cpp:305 (NewProject+0x396245)
    #5 juce::AsyncUpdater::AsyncUpdaterMessage::messageCallback() /usr/share/juce/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp:34 (NewProject+0x394800)
    #6 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /usr/share/juce/modules/juce_events/native/juce_linux_Messaging.cpp:42 (NewProject+0x3983c5)
    #7 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/11/bits/invoke.h:61 (NewProject+0x3b449f)
    #8 std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int> >::value, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/11/bits/invoke.h:154 (NewProject+0x3af8ba)
    #9 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/11/bits/std_function.h:290 (NewProject+0x3a7bb2)
    #10 std::function<void (int)>::operator()(int) const /usr/include/c++/11/bits/std_function.h:590 (NewProject+0x3a1361)
    #11 juce::InternalRunLoop::dispatchPendingEvents() <null> (NewProject+0x3995ad)
    #12 juce::dispatchNextMessageOnSystemQueue(bool) /usr/share/juce/modules/juce_events/native/juce_linux_Messaging.cpp:299 (NewProject+0x3914e3)
    #13 juce::MessageManager::runDispatchLoop() /usr/share/juce/modules/juce_events/messages/juce_MessageManager.cpp:107 (NewProject+0x389ddb)
    #14 juce::JUCEApplicationBase::main() /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (NewProject+0x388eb4)
    #15 juce::JUCEApplicationBase::main(int, char const**) /usr/share/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (NewProject+0x388d0e)
    #16 main ../../Source/Main.cpp:106 (NewProject+0x987a8)

SUMMARY: ThreadSanitizer: lock-order-inversion (potential deadlock) /usr/share/juce/modules/juce_core/native/juce_posix_SharedCode.h:39 in juce::CriticalSection::enter() const
==================

There are more errors as well but the code block restricts the size.

Please can anyone tell me how to get around these problems.

It says in the ThreadSanitizer manual that all code must be compiled (including dynamic libraries) with the flags otherwise there are false positives.

Rerunning with:

 TSAN_OPTIONS="second_deadlock_stack=1 ignore_noninstrumented_modules=1" ./NewProjectre

got rid of the errors.

2 Likes