C++ 中的线程安全字符串缓冲区变量DLL

发布于 2024-11-16 14:28:36 字数 540 浏览 2 评论 0原文

我正在 MSVC++2010 中编写带有导出函数的 Win32 DLL。其中一些函数将文件名返回为 LPCSTR。因为我之前有时需要摆弄字符串,所以我目前使用长度为 32184 的全局缓冲区变量,它应该涵盖 Windows 中可能出现的任何文件名,然后我总是在需要字符串的地方初始化并返回。

我的老板使用 VB6 遗留应用程序中的这个库。他现在告诉我他需要它是线程安全的:对我来说不幸的是,由于 VB6 的事件驱动行为,即使另一个函数尚未返回,也可能会在我的库中调用一个函数。当然,这意味着我不能依赖单个内部缓冲区,而必须在每次需要时创建一个,然后返回它。

2 个问题:

  1. 我严重依赖 Windows API 函数,例如 FindFirstFile 以及来自 filesystemregex 库的 Boost 函数。我可以假设它们都是线程安全的吗?

  2. 如果我每次想要返回字符串时都必须在堆上创建一个新缓冲区,那么我在哪里再次释放内存?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

北音执念 2024-11-23 14:28:36
  1. Windows API 函数通常是线程安全的,但有一定的限制(例如,您不能同时从两个线程在同一个句柄上FindNextFile,但可以使用两个不同的句柄)。对于 boost 函数,请参阅文档,但一般来说,只要您不在两个线程之间同时使用同一对象,文件系统/正则表达式函数应该是安全的。
  2. 当字符串处理完毕后,您必须让 VB6 应用程序回调以释放该字符串。您可能还想考虑将 DLL 编写为 COM 库;当不再需要从 COM 调用返回的 BSTR 时,VB6 将自动释放它们。
  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.
套路撩心 2024-11-23 14:28:36

VB6 代码很可能是单线程的。可重入大概仅限于 VB6 代码。 VB6 代码无法将可重入事件注入到 C++ 代码中。只要 C++ 代码不回调到 VB6 代码,那么 C++ 代码本身就不会以可重入的方式调用。

如果这些假设正确,那么您当前具有单个全局缓冲区的代码将正确运行。也就是说,在我看来,您最好切换到 BSTR,因为它允许将来链接到多线程的调用者。

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.

本宫微胖 2024-11-23 14:28:36

您可以使用 TLS 来分配字符串:



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

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文