Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.programming.threads > #534 > unrolled thread

Thread safe logging (or protecting global variables)

Started byJef Driesen <jefdriesen@hotmail.com.invalid>
First post2011-09-05 20:19 +0200
Last post2011-09-12 00:45 -0700
Articles 11 on this page of 31 — 5 participants

Back to article view | Back to comp.programming.threads


Contents

  Thread safe logging (or protecting global variables) Jef Driesen <jefdriesen@hotmail.com.invalid> - 2011-09-05 20:19 +0200
    Re: Thread safe logging (or protecting global variables) Edek <edek.pienkowski@gmail.com> - 2011-09-05 20:30 +0200
      Re: Thread safe logging (or protecting global variables) Jef Driesen <jefdriesen@hotmail.com.invalid> - 2011-09-06 18:48 +0200
        Re: Thread safe logging (or protecting global variables) Edek <edek.pienkowski@gmail.com> - 2011-09-07 10:34 +0200
          Re: Thread safe logging (or protecting global variables) Jef Driesen <jefdriesen@hotmail.com.invalid> - 2011-09-08 22:00 +0200
            Re: Thread safe logging (or protecting global variables) Edek <edek.pienkowski@gmail.com> - 2011-09-09 18:13 +0200
              Re: Thread safe logging (or protecting global variables) Jef Driesen <jefdriesen@hotmail.com.invalid> - 2011-09-13 17:58 +0200
                Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-13 13:18 -0700
                  Re: Thread safe logging (or protecting global variables) Jef Driesen <jefdriesen@hotmail.com.invalid> - 2011-09-14 07:16 +0200
                    Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-14 13:18 -0700
                  Re: Thread safe logging (or protecting global variables) Edek <edek.pienkowski@gmail.com> - 2011-09-14 09:33 +0200
                  Re: Thread safe logging (or protecting global variables) Alexander Terekhov <terekhov@web.de> - 2011-09-14 13:17 +0200
                    Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-14 13:03 -0700
                      Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-14 13:19 -0700
                      Re: Thread safe logging (or protecting global variables) "James" <no@spam.invalid> - 2011-09-14 19:19 -0700
                        Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-14 21:03 -0700
                          Re: Thread safe logging (or protecting global variables) Alexander Terekhov <terekhov@web.de> - 2011-09-15 13:12 +0200
                            Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-15 12:24 -0700
                              Re: Thread safe logging (or protecting global variables) Alexander Terekhov <terekhov@web.de> - 2011-09-15 22:22 +0200
                                Re: Thread safe logging (or protecting global variables) "James" <no@spam.invalid> - 2011-09-15 13:33 -0700
                                  Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-15 15:36 -0700
                                Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-15 15:36 -0700
                                  Re: Thread safe logging (or protecting global variables) Alexander Terekhov <terekhov@web.de> - 2011-09-16 16:28 +0200
                                    Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-16 15:06 -0700
                                      Re: Thread safe logging (or protecting global variables) Alexander Terekhov <terekhov@web.de> - 2011-09-17 12:50 +0200
                      Re: Thread safe logging (or protecting global variables) Alexander Terekhov <terekhov@web.de> - 2011-09-15 12:50 +0200
                Re: Thread safe logging (or protecting global variables) Edek <edek.pienkowski@gmail.com> - 2011-09-14 09:17 +0200
    Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-08 16:28 -0700
      Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-08 16:33 -0700
        Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-08 20:55 -0700
      Re: Thread safe logging (or protecting global variables) Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-12 00:45 -0700

Page 2 of 2 — ← Prev page 1 [2]


#574

FromJoshua Maurice <joshuamaurice@gmail.com>
Date2011-09-15 15:36 -0700
Message-ID<3230e6bf-a18d-4a64-b750-c87a275a9773@i39g2000yqn.googlegroups.com>
In reply to#572
On Sep 15, 1:33 pm, "James" <n...@spam.invalid> wrote:
> "Alexander Terekhov" <terek...@web.de> wrote in message
>
> news:4E725EA0.8D81AE41@web.de...
>
>
>
>
>
>
>
>
>
>
>
> > Joshua Maurice wrote:
> > [...]
> >> Also, I guess it particularly annoyed me that the code you linked to
>
> > You posted code
>
> >  CreateMutex(0, 1, . . .
>
> > versus my code
>
> >  CreateMutex( NULL, FALSE, . . .
>
> > See:
>
> >http://lists.boost.org/Archives/boost/2001/08/15363.php
>
> > Got it now?
>
> AFAICT, he is recursively acquiring the mutex...
>
> Joshua Maurice Code:
>
>     HANDLE namedMutex = CreateMutex(0, 1,
>             /* concoct some name which is unique to the process, ex:
>    "com.mycompany.myproject.loggingmutex" + pid */ );
>
>       WaitForSingleObject(namedMutex, INFINITE);
>
> The call to WFSO should recursively lock the mutex!

Indeed. My mistake. Whoops. That should be
    CreateMutex(0, FALSE,

[toc] | [prev] | [next] | [standalone]


#573

FromJoshua Maurice <joshuamaurice@gmail.com>
Date2011-09-15 15:36 -0700
Message-ID<d8a16350-6886-4bd3-88cd-539e691df86d@24g2000yqr.googlegroups.com>
In reply to#571
On Sep 15, 1:22 pm, Alexander Terekhov <terek...@web.de> wrote:
> Joshua Maurice wrote:
>
> [...]
>
> > Also, I guess it particularly annoyed me that the code you linked to
>
> You posted code
>
>   CreateMutex(0, 1, . . .
>
> versus my code
>
>   CreateMutex( NULL, FALSE, . . .
>
> See:
>
> http://lists.boost.org/Archives/boost/2001/08/15363.php
>
> Got it now?

Ah, yes. Typo. That is acquiring the mutex twice. It would help if in
the future you explicitly explain the problem with my code, as opposed
to merely linking to another post which lists out 4+ problems with
someone else's mostly dissimilar code. Your link doesn't even
explicitly mention that bInitialOwner argument of CreateMutex.
Apparently I was expected to divine that out of thin air.

[toc] | [prev] | [next] | [standalone]


#575

FromAlexander Terekhov <terekhov@web.de>
Date2011-09-16 16:28 +0200
Message-ID<4E735D03.6A8296D9@web.de>
In reply to#573
Joshua Maurice wrote:
[...]
> Apparently I was expected to divine that out of thin air.

I thought that you would divine that TLS lazy init is better than membar
solution, and that "1" versus "FALSE" CreateMutex() is an error.

http://lists.boost.org/Archives/boost/2001/08/15363.php

regards,
alexander.

[toc] | [prev] | [next] | [standalone]


#576

FromJoshua Maurice <joshuamaurice@gmail.com>
Date2011-09-16 15:06 -0700
Message-ID<f3f40bb4-a29d-4a45-9b69-2deb8f6fc3ba@d14g2000yqb.googlegroups.com>
In reply to#575
On Sep 16, 7:28 am, Alexander Terekhov <terek...@web.de> wrote:
> Joshua Maurice wrote:
>
> [...]
>
> > Apparently I was expected to divine that out of thin air.
>
> I thought that you would divine that TLS lazy init is better than membar
> solution, and that "1" versus "FALSE" CreateMutex() is an error.
>
> http://lists.boost.org/Archives/boost/2001/08/15363.php

Really sir. I am interesting in sharing information, and helping
others. I am not sure of the same of you. Perhaps what you said came
out badly, and we can apologize and make up. However, I feel that you
are being disingenuous and intellectually dishonest.

What you did was link to another thread without explanation, which
contains a critique of some rather naive and badly written threading
code which bears little resemblance to my own. We then spent several
posts talking about the heart of the other thread and its critiques,
which involved whether the interlocked functions have the necessary
memory synchronization semantics. No discussion was given to TLS nor
my typo in the argument of CreateMutex. After it was resolved that the
interlocked-acquire and interlocked-release are documented as having
the right semantics, you attempted to shift your position to imply
that you knew about the typo in CreateMutex the entire time, and the
entire time you meant to imply that TLS solutions are better to membar
solutions. I believe that you are being intellectually dishonest here,
that you initially found fault with my code because of interlocked,
but when you were shown to be wrong you tried to save face by finding
other problems with it.

Instead, in the future, I and the other posters would very much
appreciate if you could be intellectually honest, and concerned with
helping others. For example, if your actual concern is that I had a
mistake in the arguments of CreateMutex, you should not spend a half
dozen posts discussing whether or not the interlocked-acquire and
interlocked-release functions have acquire and release memory
synchronization semantics, and instead say something along the lines
of "You have a mistake in CreateMutex. You don't want to lock the
mutex twice. Change the second argument to FALSE." At which point, I
would have agreed, apologized for the mistake, and thanked you.

Also, if your original concern was with interlocked, but later you
found out that I had a typo in CreateMutex, then you could bring that
up without implying that was part of your critique the entire time.

Also, if you feel that the TLS solution is superior, then again
instead of doing what you did, perhaps you should have said "A
solution using TLS instead of membars is a better/faster solution. See
this example code. <code>." As I said else-thread, I was aware of some
bugs in Microsoft's implementation of TLS on some windows platforms,
and TLS is a rare resource, so don't use it at first impulse. Besides,
at least we can both agree that both solutions are correct, and
probably close to equally performant. But again, your critique said
that my code was incorrect as opposed to simply "not preferred".

Again, you seem to know what you're doing, perhaps better than I, and
I would very much appreciate your future corrections and input. It's
just that I would much prefer if you would do it in a constructive
way.

[toc] | [prev] | [next] | [standalone]


#577

FromAlexander Terekhov <terekhov@web.de>
Date2011-09-17 12:50 +0200
Message-ID<4E747B86.DE80867B@web.de>
In reply to#576
Joshua Maurice wrote:

[... much frustration ...]

See also:

http://groups.google.com/group/comp.lang.c++.moderated/msg/239fc22f57c687d4?dmode=source

regards,
alexander.

[toc] | [prev] | [next] | [standalone]


#568

FromAlexander Terekhov <terekhov@web.de>
Date2011-09-15 12:50 +0200
Message-ID<4E71D881.C5A2A4C8@web.de>
In reply to#563
Joshua Maurice wrote:

[... http://lists.boost.org/Archives/boost/2001/08/15363.php ...]

> TLS is a relatively rare precious resource (only ~1000 keys 
> available on most systems IIRC), so I'm slightly cautious where 
> I use TLS. 

Several years after 2001 Mike Burrows of Google came up with an
optimized solution to use only one TLS key for very many lazy inits:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2382.html

regards,
alexander.

[toc] | [prev] | [next] | [standalone]


#560

FromEdek <edek.pienkowski@gmail.com>
Date2011-09-14 09:17 +0200
Message-ID<j4pkjd$cav$1@node2.news.atman.pl>
In reply to#557
>
>> The third one explains how atomicity is done for many variables -
>> as long as they can be packed in one structure.
>
> I have absolutely no idea how this works.

template <class T>
atomic {
private:
    mutex m_mutex;
    T     m_val;
public:
    void set(T t) {
       scope_lock(m_mutex);

       m_val = T;
    }

    T get() {
       scope_lock(m_mutex);

       return m_val;
    }
}

The above is effectively an implementation of "atomic"
get and set (other operations elided) of T, if T
is a structure. It is simplified and unoptimised, but
it works. It works also e.g. for int, but for int
there is no need to employ a heavy mutex on most platforms.

Better implementations might use better tricks, but this
is sufficient - m_val of type T is accessed atomically.
T should be trivial enough, POD would be ok.

Edek

[toc] | [prev] | [next] | [standalone]


#551

FromJoshua Maurice <joshuamaurice@gmail.com>
Date2011-09-08 16:28 -0700
Message-ID<1d92324d-eb2e-4ada-92be-8ffb4fe8fec5@p25g2000pri.googlegroups.com>
In reply to#534
On Sep 5, 11:19 am, Jef Driesen <jefdrie...@hotmail.com.invalid>
wrote:
> Hi,
>
> I have a C library that is supposed to be thread-safe under the
> condition that you access each library object only from a single thread.
> This is done by ensuring that objects do not share any state (e.g. no
> global variables) and where necessary reentrant variants of certain C
> library functions are used (e.g. localtime_r).
>
> Now, I want to add a logging feature for debugging purposes. The idea
> would be to implement a logging infrastructure where the amount of
> output can be controlled with a loglevel parameter (defaulting to no
> output) and redirected to a file (defaulting to stderr), like in the
> pseudo code below:
>
> static int g_loglevel = 0;
> static FILE *g_logfile = stderr;
> /* Some other globals used for the logging here */
>
> message_set_loglevel (int loglevel)
> {
>     g_loglevel = loglevel;
>
> }
>
> message_set_logfile (const char *logfile)
> {
>     /* Open/close the new/old logfiles here. */
>     g_logfile = ...;
>
> }
>
> message (const char *fmt, ...)
> {
>     va_list ap;
>
>     /* This is just an example, the real code does more
>        and relies on a number of extra global variables. */
>     if (g_loglevel) {
>        va_start (ap, fmt);
>        vfprintf (g_logfile, fmt, ap);
>        va_end (ap);
>     }
>
> }
>
> Obviously, this is not thread-safe due to the use of global variables.
> Thus my next idea was to add a global mutex (e.g. pthread_mutex_t on
> unix or CRITICAL_SECTION on windows) protecting these global variables.
> But how do I initialize the mutex, considering that my library doesn't
> have (or need) any initialization functions? For the unix pthread there
> is PTHREAD_MUTEX_INITIALIZER, but as far as I know there is no such
> thing for a windows critical section? How can this problem be solved?
>
> Would it be an acceptable solution to mark the message_set_*()
> functions as not thread-safe and require applications to call them
> before/after any threads are created/destroyed? (For my use case such a
> restriction would be acceptable, although I'm not sure it would be
> fully thread-safe.) Then those functions could initialize the mutex. Or will
> that cause any trouble?
>
> Can I even go one step futher and use simple a simple flag (like the
> g_loglevel variable above) that can only be modified from the
> message_set_*() functions, and which is only checked in the message()
> function but not modified.

There may be more clever ways to do this that are runtime-faster, but
let me share some pretty easy ways to do this. You effectively need a
singleton. It can be eager initialized or lazy initialized.

For POSIX, do a lazy initialized singleton with pthread_once.
http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_once.html

For win32, do a lazy initialized singleton. Use a named mutex and the
win32 atomic (interlocked) functions to implement a correct form of
double checked locking.
http://msdn.microsoft.com/en-us/library/ms682411%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/ms683574%28v=vs.85%29.aspx

Here's a rough code sketch.
  singleton_t * getSingleton()
  {
    static LONG initFlag; //guaranteed to be 0 initialized before
runtime by C standard (IIRC)
    static singleton_t * singleton; //guaranteed to be 0 initialized
before runtime by C standard (IIRC)
    if (0 == InterlockedCompareExchangeAcquire( & initFlag, 1, 1))
    {
      HANDLE namedMutex = CreateMutex(0, 1,
            /* concoct some name which is unique to the process, ex:
"com.mycompany.myproject.loggingmutex" + pid */ );
      WaitForSingleObject(namedMutex, INFINITE);
      if (0 == InterlockedCompareExchangeAcquire( & initFlag, 1, 1))
      {
        singleton = //init singleton;
        InterlockedCompareExchangeRelease( & intFlag, 1, 0);
      }
      ReleaseMutex(namedMutex);
    }
    return singleton;
  }

I think that's right, or at least it should point you in the right
direction. I don't guarantee its correctness, and you ought to double
check that all works right.

[toc] | [prev] | [next] | [standalone]


#552

FromJoshua Maurice <joshuamaurice@gmail.com>
Date2011-09-08 16:33 -0700
Message-ID<cc4c3890-d6c8-4ae0-aee5-872a95c74386@v16g2000prb.googlegroups.com>
In reply to#551
On Sep 8, 4:28 pm, Joshua Maurice <joshuamaur...@gmail.com> wrote:
> On Sep 5, 11:19 am, Jef Driesen <jefdrie...@hotmail.com.invalid>
> wrote:
>
>
>
>
>
>
>
>
>
> > Hi,
>
> > I have a C library that is supposed to be thread-safe under the
> > condition that you access each library object only from a single thread.
> > This is done by ensuring that objects do not share any state (e.g. no
> > global variables) and where necessary reentrant variants of certain C
> > library functions are used (e.g. localtime_r).
>
> > Now, I want to add a logging feature for debugging purposes. The idea
> > would be to implement a logging infrastructure where the amount of
> > output can be controlled with a loglevel parameter (defaulting to no
> > output) and redirected to a file (defaulting to stderr), like in the
> > pseudo code below:
>
> > static int g_loglevel = 0;
> > static FILE *g_logfile = stderr;
> > /* Some other globals used for the logging here */
>
> > message_set_loglevel (int loglevel)
> > {
> >     g_loglevel = loglevel;
>
> > }
>
> > message_set_logfile (const char *logfile)
> > {
> >     /* Open/close the new/old logfiles here. */
> >     g_logfile = ...;
>
> > }
>
> > message (const char *fmt, ...)
> > {
> >     va_list ap;
>
> >     /* This is just an example, the real code does more
> >        and relies on a number of extra global variables. */
> >     if (g_loglevel) {
> >        va_start (ap, fmt);
> >        vfprintf (g_logfile, fmt, ap);
> >        va_end (ap);
> >     }
>
> > }
>
> > Obviously, this is not thread-safe due to the use of global variables.
> > Thus my next idea was to add a global mutex (e.g. pthread_mutex_t on
> > unix or CRITICAL_SECTION on windows) protecting these global variables.
> > But how do I initialize the mutex, considering that my library doesn't
> > have (or need) any initialization functions? For the unix pthread there
> > is PTHREAD_MUTEX_INITIALIZER, but as far as I know there is no such
> > thing for a windows critical section? How can this problem be solved?
>
> > Would it be an acceptable solution to mark the message_set_*()
> > functions as not thread-safe and require applications to call them
> > before/after any threads are created/destroyed? (For my use case such a
> > restriction would be acceptable, although I'm not sure it would be
> > fully thread-safe.) Then those functions could initialize the mutex. Or will
> > that cause any trouble?
>
> > Can I even go one step futher and use simple a simple flag (like the
> > g_loglevel variable above) that can only be modified from the
> > message_set_*() functions, and which is only checked in the message()
> > function but not modified.
>
> There may be more clever ways to do this that are runtime-faster, but
> let me share some pretty easy ways to do this. You effectively need a
> singleton. It can be eager initialized or lazy initialized.
>
> For POSIX, do a lazy initialized singleton with pthread_once.http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_once.html
>
> For win32, do a lazy initialized singleton. Use a named mutex and the
> win32 atomic (interlocked) functions to implement a correct form of
> double checked locking.http://msdn.microsoft.com/en-us/library/ms682411%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms683574%28v=vs.85%29.aspx
>
> Here's a rough code sketch.
>   singleton_t * getSingleton()
>   {
>     static LONG initFlag; //guaranteed to be 0 initialized before
> runtime by C standard (IIRC)
>     static singleton_t * singleton; //guaranteed to be 0 initialized
> before runtime by C standard (IIRC)
>     if (0 == InterlockedCompareExchangeAcquire( & initFlag, 1, 1))
>     {
>       HANDLE namedMutex = CreateMutex(0, 1,
>             /* concoct some name which is unique to the process, ex:
> "com.mycompany.myproject.loggingmutex" + pid */ );
>       WaitForSingleObject(namedMutex, INFINITE);
>       if (0 == InterlockedCompareExchangeAcquire( & initFlag, 1, 1))
>       {
>         singleton = //init singleton;
>         InterlockedCompareExchangeRelease( & intFlag, 1, 0);
>       }
>       ReleaseMutex(namedMutex);
>     }
>     return singleton;
>   }
>
> I think that's right, or at least it should point you in the right
> direction. I don't guarantee its correctness, and you ought to double
> check that all works right.

Hmm, of course, you could use the acquire and release variants of
InterlockedCompareExchangePointer
http://msdn.microsoft.com/en-us/library/ms683568%28v=vs.85%29.aspx
to get rid of the unnecessary init flag.

[toc] | [prev] | [next] | [standalone]


#553

FromJoshua Maurice <joshuamaurice@gmail.com>
Date2011-09-08 20:55 -0700
Message-ID<0684715d-07cb-4ab8-a684-81794367e463@y39g2000prd.googlegroups.com>
In reply to#552
On Sep 8, 4:33 pm, Joshua Maurice <joshuamaur...@gmail.com> wrote:
> On Sep 8, 4:28 pm, Joshua Maurice <joshuamaur...@gmail.com> wrote:
>
>
>
>
>
>
>
>
>
> > On Sep 5, 11:19 am, Jef Driesen <jefdrie...@hotmail.com.invalid>
> > wrote:
>
> > > Hi,
>
> > > I have a C library that is supposed to be thread-safe under the
> > > condition that you access each library object only from a single thread.
> > > This is done by ensuring that objects do not share any state (e.g. no
> > > global variables) and where necessary reentrant variants of certain C
> > > library functions are used (e.g. localtime_r).
>
> > > Now, I want to add a logging feature for debugging purposes. The idea
> > > would be to implement a logging infrastructure where the amount of
> > > output can be controlled with a loglevel parameter (defaulting to no
> > > output) and redirected to a file (defaulting to stderr), like in the
> > > pseudo code below:
>
> > > static int g_loglevel = 0;
> > > static FILE *g_logfile = stderr;
> > > /* Some other globals used for the logging here */
>
> > > message_set_loglevel (int loglevel)
> > > {
> > >     g_loglevel = loglevel;
>
> > > }
>
> > > message_set_logfile (const char *logfile)
> > > {
> > >     /* Open/close the new/old logfiles here. */
> > >     g_logfile = ...;
>
> > > }
>
> > > message (const char *fmt, ...)
> > > {
> > >     va_list ap;
>
> > >     /* This is just an example, the real code does more
> > >        and relies on a number of extra global variables. */
> > >     if (g_loglevel) {
> > >        va_start (ap, fmt);
> > >        vfprintf (g_logfile, fmt, ap);
> > >        va_end (ap);
> > >     }
>
> > > }
>
> > > Obviously, this is not thread-safe due to the use of global variables.
> > > Thus my next idea was to add a global mutex (e.g. pthread_mutex_t on
> > > unix or CRITICAL_SECTION on windows) protecting these global variables.
> > > But how do I initialize the mutex, considering that my library doesn't
> > > have (or need) any initialization functions? For the unix pthread there
> > > is PTHREAD_MUTEX_INITIALIZER, but as far as I know there is no such
> > > thing for a windows critical section? How can this problem be solved?
>
> > > Would it be an acceptable solution to mark the message_set_*()
> > > functions as not thread-safe and require applications to call them
> > > before/after any threads are created/destroyed? (For my use case such a
> > > restriction would be acceptable, although I'm not sure it would be
> > > fully thread-safe.) Then those functions could initialize the mutex. Or will
> > > that cause any trouble?
>
> > > Can I even go one step futher and use simple a simple flag (like the
> > > g_loglevel variable above) that can only be modified from the
> > > message_set_*() functions, and which is only checked in the message()
> > > function but not modified.
>
> > There may be more clever ways to do this that are runtime-faster, but
> > let me share some pretty easy ways to do this. You effectively need a
> > singleton. It can be eager initialized or lazy initialized.
>
> > For POSIX, do a lazy initialized singleton with pthread_once.http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_once.html
>
> > For win32, do a lazy initialized singleton. Use a named mutex and the
> > win32 atomic (interlocked) functions to implement a correct form of
> > double checked locking.http://msdn.microsoft.com/en-us/library/ms682411%28v=vs.85%29.aspxhtt...
>
> > Here's a rough code sketch.
> >   singleton_t * getSingleton()
> >   {
> >     static LONG initFlag; //guaranteed to be 0 initialized before
> > runtime by C standard (IIRC)
> >     static singleton_t * singleton; //guaranteed to be 0 initialized
> > before runtime by C standard (IIRC)
> >     if (0 == InterlockedCompareExchangeAcquire( & initFlag, 1, 1))
> >     {
> >       HANDLE namedMutex = CreateMutex(0, 1,
> >             /* concoct some name which is unique to the process, ex:
> > "com.mycompany.myproject.loggingmutex" + pid */ );
> >       WaitForSingleObject(namedMutex, INFINITE);
> >       if (0 == InterlockedCompareExchangeAcquire( & initFlag, 1, 1))
> >       {
> >         singleton = //init singleton;
> >         InterlockedCompareExchangeRelease( & intFlag, 1, 0);
> >       }
> >       ReleaseMutex(namedMutex);
> >     }
> >     return singleton;
> >   }
>
> > I think that's right, or at least it should point you in the right
> > direction. I don't guarantee its correctness, and you ought to double
> > check that all works right.
>
> Hmm, of course, you could use the acquire and release variants of
> InterlockedCompareExchangePointerhttp://msdn.microsoft.com/en-us/library/ms683568%28v=vs.85%29.aspx
> to get rid of the unnecessary init flag.

That is annoying. I believe the code that I posted is correct, more or
less. However, a simple acquire-read and release-write for pointer
objects and values would be better. Perhaps InterlockedAddAcquire and
InterlockedAddRelease, or the OR pairs, AND pairs, etc., on the
pointer object itself. You'd have to ifdef based on the size of the
pointer, and I don't know what would be fastest.

[toc] | [prev] | [next] | [standalone]


#556

FromJoshua Maurice <joshuamaurice@gmail.com>
Date2011-09-12 00:45 -0700
Message-ID<47dbcabb-ff9c-45c6-bc7d-d958eb2f7a75@d14g2000yqb.googlegroups.com>
In reply to#551
On Sep 8, 4:28 pm, Joshua Maurice <joshuamaur...@gmail.com> wrote:
> On Sep 5, 11:19 am, Jef Driesen <jefdrie...@hotmail.com.invalid>
> wrote:
>
>
>
>
>
>
>
>
>
> > Hi,
>
> > I have a C library that is supposed to be thread-safe under the
> > condition that you access each library object only from a single thread.
> > This is done by ensuring that objects do not share any state (e.g. no
> > global variables) and where necessary reentrant variants of certain C
> > library functions are used (e.g. localtime_r).
>
> > Now, I want to add a logging feature for debugging purposes. The idea
> > would be to implement a logging infrastructure where the amount of
> > output can be controlled with a loglevel parameter (defaulting to no
> > output) and redirected to a file (defaulting to stderr), like in the
> > pseudo code below:
>
> > static int g_loglevel = 0;
> > static FILE *g_logfile = stderr;
> > /* Some other globals used for the logging here */
>
> > message_set_loglevel (int loglevel)
> > {
> >     g_loglevel = loglevel;
>
> > }
>
> > message_set_logfile (const char *logfile)
> > {
> >     /* Open/close the new/old logfiles here. */
> >     g_logfile = ...;
>
> > }
>
> > message (const char *fmt, ...)
> > {
> >     va_list ap;
>
> >     /* This is just an example, the real code does more
> >        and relies on a number of extra global variables. */
> >     if (g_loglevel) {
> >        va_start (ap, fmt);
> >        vfprintf (g_logfile, fmt, ap);
> >        va_end (ap);
> >     }
>
> > }
>
> > Obviously, this is not thread-safe due to the use of global variables.
> > Thus my next idea was to add a global mutex (e.g. pthread_mutex_t on
> > unix or CRITICAL_SECTION on windows) protecting these global variables.
> > But how do I initialize the mutex, considering that my library doesn't
> > have (or need) any initialization functions? For the unix pthread there
> > is PTHREAD_MUTEX_INITIALIZER, but as far as I know there is no such
> > thing for a windows critical section? How can this problem be solved?
>
> > Would it be an acceptable solution to mark the message_set_*()
> > functions as not thread-safe and require applications to call them
> > before/after any threads are created/destroyed? (For my use case such a
> > restriction would be acceptable, although I'm not sure it would be
> > fully thread-safe.) Then those functions could initialize the mutex. Or will
> > that cause any trouble?
>
> > Can I even go one step futher and use simple a simple flag (like the
> > g_loglevel variable above) that can only be modified from the
> > message_set_*() functions, and which is only checked in the message()
> > function but not modified.
>
> There may be more clever ways to do this that are runtime-faster, but
> let me share some pretty easy ways to do this. You effectively need a
> singleton. It can be eager initialized or lazy initialized.
>
> For POSIX, do a lazy initialized singleton with pthread_once.http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_once.html
>
> For win32, do a lazy initialized singleton. Use a named mutex and the
> win32 atomic (interlocked) functions to implement a correct form of
> double checked locking.http://msdn.microsoft.com/en-us/library/ms682411%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms683574%28v=vs.85%29.aspx
>
> Here's a rough code sketch.
>   singleton_t * getSingleton()
>   {
>     static LONG initFlag; //guaranteed to be 0 initialized before
> runtime by C standard (IIRC)
>     static singleton_t * singleton; //guaranteed to be 0 initialized
> before runtime by C standard (IIRC)
>     if (0 == InterlockedCompareExchangeAcquire( & initFlag, 1, 1))
>     {
>       HANDLE namedMutex = CreateMutex(0, 1,
>             /* concoct some name which is unique to the process, ex:
> "com.mycompany.myproject.loggingmutex" + pid */ );
>       WaitForSingleObject(namedMutex, INFINITE);
>       if (0 == InterlockedCompareExchangeAcquire( & initFlag, 1, 1))
>       {
>         singleton = //init singleton;
>         InterlockedCompareExchangeRelease( & intFlag, 1, 0);
>       }
>       ReleaseMutex(namedMutex);
>     }
>     return singleton;
>   }
>
> I think that's right, or at least it should point you in the right
> direction. I don't guarantee its correctness, and you ought to double
> check that all works right.

Oh, and I think windows implemented an equivalent for pthread_once,
but only for vista or higher. (Again, IIRC.) I used to really care
about XP, but perhaps now that that is being phased out...

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.programming.threads


csiph-web