Как связать не потокобезопасную библиотеку, чтобы у каждого потока были свои глобальные переменные? - PullRequest
5 голосов
/ 15 сентября 2010

У меня есть программа, которую я связываю со многими библиотеками.Я запустил свое приложение на профилировщике и обнаружил, что большая часть времени проводится в состоянии ожидания после некоторых сетевых запросов.Эти запросы являются результатом моего вызова кода sleeping_function() из внешней библиотеки.Я вызываю эту функцию в цикле, который выполняется много-много раз, поэтому все время ожидания сводится к огромным суммам.

Поскольку я не могу изменить sleeping_function(), я хочу запустить несколько потоков для запуска нескольких итерациймой цикл параллельно.Проблема заключается в том, что эта функция внутренне использует некоторые глобальные переменные.

Есть ли способ сообщить компоновщику в SunOS, что я хочу связать определенные библиотеки таким образом, чтобы все переменные из них помещались в Thread Local Storage?

Ответы [ 2 ]

1 голос
/ 15 сентября 2010

В общем, это плохая идея. Глобальные данные - не единственная проблема, которая может помешать работе многопоточной среды без поточной библиотеки.

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

1 голос
/ 15 сентября 2010

Я не думаю, что вы сможете достичь этого только с помощью компоновщика, но вы можете получить что-то, работающее с некоторым кодом в C.

Проблема в том, что вызов loadбиблиотека, которая уже загружена, возвратит ссылку на уже загруженный экземпляр вместо загрузки новой копии.Беглый взгляд на документацию для dlopen и LoadLibrary , кажется, подтверждает, что невозможно загрузить одну и ту же библиотеку более одного раза, по крайней мере, если вы хотите, чтобы изображение было подготовленовыполнение.Один из способов обойти это - запретить ОС знать, что это одна и та же библиотека.Для этого вы можете сделать копию файла.

Какой-то псевдокод, просто замените звонки на sleeping_function звонками на call_sleeping_function_thread_safe:

char *shared_lib_name

void sleeping_function_thread_init(char *lib_name);

void call_sleeping_function_thread_safe()
{
  void *lib_handle;
  pthread_t pthread;
  new_file_name = make_copy_of_file(shared_lib_name);

  pthread_create(&pthread, NULL, sleeping_function_thread_init, new_file_name);
}

void sleeping_function_thread_init(char *lib_name)
{
  void *lib_handle;
  void (*)() sleeping_function;

  lib_handle = dlopen(lib_name, RTLD_LOCAL);
  sleeping_function = dlsym(lib_handle, "sleeping_function")
  while (...)
    sleeping_function;
  dlclose(lib_handle);
  delete_file(lib_name);      
}

Для Windows dlopenстановится LoadLibrary и dlsym становится GetProcAddress и т. д. ... но основная идея все равно будет работать.

...