std::mutex bug: Windows handle growth
Frank Eskesen via Cygwin <[email protected]>
| Newsgroups | gmane.os.cygwin |
|---|---|
| Message-ID | <[email protected]> |
I've run into a problem that occurs on Cygwin that doesn't occur on Linux
systems: When a std::mutex is used, it doesn't clean up a Windows handle
that
it uses. This sample program demonstrates the problem, failing in under 60
seconds. Run this while using Window task manager to watch the handle count
rise. On my machine, the count rapidly grows to about 16 million and then a
std::exception is thrown.
When commenting out the lock_guard statement, there is no handle growth.
When changing the lock_guard to mutex.lock(), the handle growth increases
until an exception is thrown.
Surprisingly, when changing the lock_guard to mutex.unlock() handle growth
increases to about 16,880,000 and doesn't increase more. No exception
occurs.
(mutex::unlock without mutex::lock is apparently allowed.)
The "Invalid argument" exception is presumably thrown somewhere in the mutex
locking code.
Console output:
/home/*******/obj/cpp/Test: Test_mutex
FAILED: Exception: exception(Invalid argument)
//----------------------------------------------------------------------------
//
// Title-
// Test_mutex.cpp
//
// Purpose-
// Mutex stress test.
//
// Last change date-
// 2026/03/16
//
//----------------------------------------------------------------------------
#include <exception> // For std::exception
#include <mutex> // For std::mutex
#include <cstdio> // For printf
#include <ctime> // For timespec, clock_gettime
//----------------------------------------------------------------------------
// Constants for parameterization
//----------------------------------------------------------------------------
static double opt_runtime= 60.0; // --runtime option
//----------------------------------------------------------------------------
//
// Subroutine-
// now
//
// Purpose-
// Return the number of seconds since the PC epoch.
//
//----------------------------------------------------------------------------
static double // Seconds since the PC epoch
now( void ) // Get the current time
{
struct timespec ticker; // UTC time base
clock_gettime(CLOCK_REALTIME, &ticker); //
double seconds= (double)ticker.tv_sec;
seconds += (double)ticker.tv_nsec / 1000000000.0;
return seconds;
}
//----------------------------------------------------------------------------
//
// Subroutine-
// do_something
//
// Purpose-
// Do something that causes CYGWIN handle growth
//
//----------------------------------------------------------------------------
static void
do_something(void) // Try to cause CYGWIN handle growth
{
std::mutex mutex;
std::lock_guard<decltype(mutex)> lock(mutex);
}
//----------------------------------------------------------------------------
//
// Subroutine-
// test_mutex
//
// Purpose-
// std::mutex stress test.
//
//----------------------------------------------------------------------------
static inline void
test_mutex( void ) // Timing test
{
double then= now(); // Running timer
while( (now() - then) < opt_runtime )
do_something();
}
//----------------------------------------------------------------------------
//
// Subroutine-
// main
//
// Purpose-
// Mainline code.
//
//----------------------------------------------------------------------------
extern int
main(int, char**) // Mainline code
{
try {
test_mutex();
} catch(std::exception& x) {
printf("FAILED: Exception: exception(%s)\n", x.what());
} catch(...) {
printf("FAILED: Exception: ...\n");
}
return 0;
}
--
Problem reports: https://cygwin.com/problems.html
FAQ: https://cygwin.com/faq/
Documentation: https://cygwin.com/docs.html
Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple