On 2024-01-19 20:18, Takashi Yano via Cygwin wrote:
> And I tried to observe the pthread_mutex_xxx() call. Then found the
> test case does like:
> 
> #include <pthread.h>
> int main()
> {
>   for (;;) {
>     pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
>     pthread_mutex_lock(&m);
>     pthread_mutex_unlock(&m);
>   }
>   return 0;
> }

Note POSIX:

In cases where default mutex attributes are appropriate,
the macro PTHREAD_MUTEX_INITIALIZER can be used to initialize
mutexes. The effect shall be equivalent to dynamic initialization
by a call to pthread_mutex_init() with parameter attr specified as NULL,
except that no error checks are performed.

Thus, the following is correct:

   for (;;) {
     pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
     pthread_mutex_lock(&m);
     pthread_mutex_unlock(&m);
     pthread_mutex_destroy(&m); // <--- added
   }

Does your above code leak if you add the destroy call?

If so, pthread_mutex_destroy needs to be fixed.

Either way, libstdc++ should be calling pthread_mutex_destroy
in the destructor, in spite of initializing the object with
a simple initializer.

That libstdc++ library could be fixed in the same way;
the mutex object's destructor should call pthread_mutex_destroy,
even though the constructor didn't call pthread_mutex_init.

This is a "moral equivalent":

  class buf {
    unsigned char *ptr;
  public:
    buf() : ptr(NULL) { }
    ~buf() { delete [] ptr; }
    // ...
  };

Just because you have a constructor that trivially initializes
some resource with a constant expression doesn't mean that the
destructor has nothing to free. In between there the object
is mutated so that it holds resources.


> POSIX states pthread_mutex_t can be initialized with
> PTREAD_MUTEX_INITIALZER when it is STATICALLY allocated.

I'm looking at this and don't see such a constraint:

https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_destroy.html

The word "static" only occurs in the Rationale section.

Use of the initializer is not restricted to static objects
by any normative wording.

In real systems, the static distinction has no meaning.

This code can be inside a shared library:

   static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;

this library could be loaded by dlopen and unloaded with dlclose.
Thus static becomes dynamic!

And, by the way, this is a problem: if we have a library
which does the above, and we repeatedly load it and unload
it while using the mutex in between, it will leak.

I think you don't want to do this kind of initialization in
reloadable plugins, unless you put in some destructor hooks,
or wrap it with C++ objects with destructors.

-- 
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

Reply via email to