16

Is

OutputDebugString(PAnsiChar(''));

thread safe?

I/we have been using it in threads for debugging, and it never occurred to me if I should be doing it a different way.

(Delphi 7)

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Christopher Chase
  • 2,728
  • 5
  • 34
  • 54

3 Answers3

26

Well, not that it isn't true, it is, but just so that you don't have to just take Lieven word for it:

Passing of data between the application and the debugger is done via a 4kbyte chunk of shared memory, with a Mutex and two Event objects protecting access to it. These are the four kernel objects involved.

Understanding Win32 OutputDebugString is an excellent article on the matter.

Jorge Córdoba
  • 47,433
  • 11
  • 77
  • 126
  • I knew it was threadsafe because I once had to look it up myself. I didn't know the entire story behind it anymore though. Thanks for clarifying it. – Lieven Keersmaekers Feb 04 '09 at 00:05
18

Don't worry, it is.

When OutputDebugString() is called by an application, it takes these steps. Note that a failure at any point abandons the whole thing and treats the debugging request as a no-op (the string isn't sent anywhere).

  1. Open DBWinMutex and wait until we have exclusive access to it.
  2. Map the DBWIN_BUFFER segment into memory: if it's not found, there is no debugger running so the entire request is ignored.
  3. Open the DBWIN_BUFFER_READY and DBWIN_DATA_READY events. As with the shared memory segment, missing objects mean that no debugger is available.
  4. Wait for the DBWIN_BUFFER_READY event to be signaled: this says that the memory buffer is no longer in use. Most of the time, this event will be signaled immediately when it's examined, but it won't wait longer than 10 seconds for the buffer to become ready (a timeout abandons the request).
  5. Copy up to about 4kbytes of data to the memory buffer, and store the current process ID there as well. Always put a NUL byte at the end of the string.
  6. Tell the debugger that the buffer is ready by setting the DBWIN_DATA_READY event. The debugger takes it from there.
  7. Release the mutex
  8. Close the Event and Section objects, though we keep the handle to the mutex around for later.
Lieven Keersmaekers
  • 53,391
  • 11
  • 100
  • 140
3

I've had trouble once, though, with strings in an ISAPI DLL. For some odd reason the IsMultiThread boolean defined in System.pas was not set!

It was causing weird AccessViolations, once the thread was running more than one thread... A simple "IsMultiThread:=true;" in a unit initialization fixed it.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
  • @Stijn, what version of Delphi was this? When I break on my Delphi 2007 app, the IDE shows this variable as `true`. – rossmcm Jul 16 '15 at 22:38