简体   繁体   中英

Thread-safe string buffer variables in C++ DLL

I am writing a Win32 DLL in MSVC++2010 with exported functions. Some of those functions return filenames as LPCSTR . Because I sometimes need to fiddle with strings before, I am currently using a global buffer variable of length 32184 which should cover any filename that can occur in Windows which I then always initialize and return where a string is needed.

My boss uses this library from a VB6 legacy app. He now informed me that he needs it to be thread-safe: unfortunately for me, due to VB6's event-driven behaviour, it can happen that a function is called in my library even if another function has not yet returned. This, of course, means that I cannot rely on a single internal buffer but have to create one every time I need one and then return it.

2 Questions:

  1. I rely heavily on Windows API functions such as FindFirstFile and Boost functions from the filesystem and regex libraries. Can I assume that they are all thread-safe?

  2. If I have to create a new buffer on the heap every time I want to return a string, where do I free the memory again?

  1. Windows API functions are generally thread-safe, with certain limitations (eg, you cannot FindNextFile on the same handle from two threads at the same time, but you can with two different handles). For boost functions, consult the documentation, but generally speaking filesystem/regex functions should be safe as long as you don't use the same object between two threads at the same time.
  2. You will have to have the VB6 app call back to free the string when it's done with it. You may also want to consider writing your DLL as a COM library; BSTRs returned from COM calls will be automatically freed by VB6 when they're no longer needed.

The VB6 code is most probably single threaded. The re-entrancy is presumably limited to the VB6 code. The VB6 code can't inject re-entrant events into the C++ code. So long as the C++ code does not call back into the VB6 code then the C++ code itself will not be called in re-entrant fashion.

If these presumptions are correct then your current code with a single global buffer will operate correctly. That said you would be better off switching to BSTR in my view because it would allow for future linking against caller's that were multi-threaded.

You can use TLS for allocation the string:



const int string_size = 1024; // string size 
DWORD idTlsString = 0;


// use this function to get the string which you will use to return to VB
char* GetTheString()
{
    return (char*)TlsGetValue(idTlsString);
}

// Dll init function
BOOL WINAPI DllMain(
  HINSTANCE hinstDLL,
  DWORD fdwReason,
  LPVOID lpvReserved
)
{
   switch( fdwReason )
   {
       // allocate TSL
       case DLL_PROCESS_ATTACH:
          idTlsString = TlsAlloc();
       break;

       // allocate the srting
       case DLL_THREAD_ATTACH:
          TlsSetValue(idTlsString, (LPVOID)new char[string_size] );
       break;

       // free the string
       case DLL_THREAD_DETACH:
          delete[] (char*)TlsGetValue(idTlsString);
       break;

       // release TLS
       case DLL_PROCESS_DETACH:
          TlsFree(idTlsString);
       break;

   }
   return true;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM