Потоково-безопасные строковые буферные переменные в C ++ DLL - PullRequest
0 голосов
/ 22 июня 2011

Я пишу Win32 DLL в MSVC ++ 2010 с экспортированными функциями. Некоторые из этих функций возвращают имена файлов как LPCSTR. Так как мне иногда приходится возиться со строками раньше, я в настоящее время использую глобальную буферную переменную длиной 32184, которая должна охватывать любое имя файла, которое может возникнуть в Windows, которое я затем всегда инициализирую и возвращаю, где нужна строка.

Мой босс использует эту библиотеку из унаследованного приложения VB6. Теперь он сообщил мне, что ему нужно, чтобы он был потокобезопасным: к сожалению, из-за поведения VB6, управляемого событиями, может случиться так, что функция вызывается в моей библиотеке, даже если другая функция еще не возвращена. Это, конечно, означает, что я не могу полагаться на один внутренний буфер, но мне приходится создавать его каждый раз, когда он мне нужен, а затем возвращать его.

2 вопроса:

  1. Я сильно полагаюсь на функции Windows API, такие как FindFirstFile и функции Boost из библиотек filesystem и regex. Могу ли я предположить, что они все потокобезопасны?

  2. Если мне нужно создавать новый буфер в куче каждый раз, когда я хочу вернуть строку, где мне снова освободить память?

Ответы [ 3 ]

3 голосов
/ 22 июня 2011
  1. Функции Windows API, как правило, являются поточно-ориентированными, с некоторыми ограничениями (например, вы не можете FindNextFile на одном дескрипторе из двух потоков одновременно, но вы можете использовать с двумя разными дескрипторами). Что касается функций повышения, обратитесь к документации, но в целом функции файловой системы / регулярных выражений должны быть безопасными, если вы не используете один и тот же объект между двумя потоками одновременно.
  2. Вам потребуется обратный вызов приложения VB6, чтобы освободить строку, когда она будет завершена. Вы также можете рассмотреть возможность написания своей DLL как библиотеки COM; BSTR, возвращенные из вызовов COM, будут автоматически освобождены VB6, когда они больше не нужны.
1 голос
/ 22 июня 2011

Код VB6, скорее всего, является однопоточным.Повторный вход предположительно ограничен кодом VB6.Код VB6 не может вводить повторно поступающие события в код C ++.До тех пор, пока код C ++ не вызывает обратный вызов в коде VB6, сам код C ++ не будет вызываться повторно.

Если эти предположения верны, то ваш текущий код с одним глобальным буфером будетдействуй правильно.Тем не менее, на мой взгляд, вам было бы лучше перейти на BSTR, поскольку это позволило бы в будущем связываться с вызывающими, которые были многопоточными.

0 голосов
/ 23 июня 2011

Вы можете использовать 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...