Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» TlsAlloc() --> TlsFree(.) --> TlsAll

Автор: Igorr
Дата сообщения: 08.07.2005 18:19
В dll использую thread local storage (TLS) index для хранения указателя данных потока, создаваемого внутри dll. До недавнего времени обращений для создания TSL индекса функцией TlsAlloc() и его освобождения функцией TlsFree(.) в задаче было 2-3 раза и никаких проблем не наблюдалось. Сейчас понадобилось делать около 10000 обращений - и обнаружилась очень неприятная вещь:

с увеличением количества вызовов TlsAlloc() --> TlsFree(.) --> TlsAlloc() --> TlsFree(.) --> ... время выполнения этих функций (или одной из них - не могу определить) увеличивается катастрофически - после 14 обращений TlsAlloc() + TlsFree(.) ~ на 2.5% по сравнению с выполнением предыдущих 14 вызовов.

А это значит, что после 100 раз по 14 обращений время увеличивается ~ в 12 раз (проверил); после 200 раз - в 140 раз !!! (не проверил).
Что это за дела и как с этим бороться?

dll сделана на Compaq Visual Fortran 6.6, вызывается из VC++ программы (VS.NET 2003) в Win2003.
Автор: mr_eoi
Дата сообщения: 09.07.2005 06:05
Igorr
Посмотри здесь:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/using_thread_local_storage_in_a_dynamic_link_library.asp
может поможет.
Автор: Igorr
Дата сообщения: 09.07.2005 18:19
mr_eoi
это один из примеров использования TSL, но нет никакой информации о временах выполнения TSL-функций и возможных нюансов от их много-много кратно повторяемых вызовов.
Автор: OldGopher
Дата сообщения: 09.07.2005 22:58
Я не понял, имеется в виду, что одновременно используется так много зон сохранения?
Их всего может быть (ИМХО) 4096 в Windows 2000+...

Я никогда не натыкался на необходимость иметь так много TLS. Сам никогда не заказывал более одной.
Можно поподробнее, почему возникла такая необходимость?
Автор: Igorr
Дата сообщения: 10.07.2005 00:55
зон сохранения одна (иногда бывает до трех);
TlsAlloc(), TlsFree(.) находятся в dll-ной функции к которой происходит несколько десятков тысяч обращений; и с каждым разом время выполнения этих функций увеличивается .
Автор: segeich
Дата сообщения: 10.07.2005 03:38
Igorr

Цитата:
TlsAlloc(), TlsFree(.) находятся в dll-ной функции к которой происходит несколько десятков тысяч обращений

Нафига использовать TLS, если Alloc и Free вызываются внутри одной функции??? Не проще ли обойтись обычной локальной переменной?

А замедление возможно объясняется вот этим замечанием из описания TlsFree в MSDN:

Цитата:
It is expected that DLLs call this function (if at all) only during DLL_PROCESS_DETACH.
Автор: mr_eoi
Дата сообщения: 10.07.2005 05:31

Цитата:
А замедление возможно объясняется вот этим замечанием из описания TlsFree в MSDN:
It is expected that DLLs call this function (if at all) only during DLL_PROCESS_DETACH

Именно это и демонстрирует приведённая мною ссылка.
Автор: Igorr
Дата сообщения: 10.07.2005 06:04
segeich

Цитата:
Нафига использовать TLS, если Alloc и Free вызываются внутри одной функции??? Не проще ли обойтись обычной локальной переменной?

так я бы с радостью, если бы один поток спользовал dll, а то используют одновременно до 3 - потому и применяю TLS, иначе - незачем.
Автор: mr_eoi
Дата сообщения: 10.07.2005 07:34
Igorr
Так для того и создаётся TLS индекс, чтобы потоки промеж себя за глобали не передрались. Далее TlsGetData и TlsSetData персонализируют этот индекс конкрентно для вызывающего их потока. Т.о. одним индексом, неперекаясь, могут пользоваться сколько угодно потоков данного процесса. Имнно поэтому TlsAlloc и TlsFree можно спокойно вызывать в обработчиах DLL_PROCESS_ATTACH и DLL_PROCESS_DETACH соответственно. В противном случае TLS вообще не имело бы никакого смысла.
Автор: Igorr
Дата сообщения: 10.07.2005 08:56
mr_eoi
это не совсем по теме: речь не идет о том зачем нужен TLS (в MSDN достаточно хорошо это прописано), а о том, что возникают побочные эффекты и как с ними бороться. Я подозреваю, что где-то, что-то накапливается, но не пойму где и что, и главное - по моей ли вине или нет.
Автор: mr_eoi
Дата сообщения: 10.07.2005 10:05
Igorr
Похоже твой вопрос носит чисто академический а не практический характер. Иначе непонятно, зачем вызывать пары TlsAlloc/TlsFree неимоверное количество раз в рамках одного процесса (похоже разработчикам данного механизма и в голову не могло прийти такое - отсюда и тормоза).
IMHO, пара TlsAlloc/TlsFree должна выполняться один единственный раз при загрузке и выгрузке DLL соответственно.
Автор: segeich
Дата сообщения: 10.07.2005 13:09
Igorr

Цитата:
так я бы с радостью, если бы один поток спользовал dll, а то используют одновременно до 3 - потому и применяю TLS, иначе - незачем.

TLS используют в DLL, если выполняются два условия:
1) Функции DLL могут вызываться из разных потоков
2) Нужно сохранять некоторы данные между вызовами этих функций, причем данные для каждого потока - свои.

Если же я правильно понял твои предыдущие посты, то TlsAlloc и TlsFree у тебя вызываются внутри одной и той же функции, т.е. усовие 2) не выполняется. Нафига тогда TLS???
Автор: Igorr
Дата сообщения: 10.07.2005 19:15
mr_eoi
OldGopher
segeich

Сделано следующим образом:

в VC++:

FuncVC:
1) hThreadVC = ::CreateThread(ThreadVC,...);
2) ::WaitForSingleObject(hThreadVC,...);
( 1) и 2) сделаны так из-за того, что был уже готовый вариант с FuncVC_0:
1) AfxBeginThread(ThreadVC,...);
она вызывалась 3 раза - и считались одновременно 3 расчетных варианта задачи в Visual Fortran (VF); ждать возврата из ThreadVC не надо было, а теперь понадобилось его ждать)

ThreadVC:
3) HDll = ::LoadLibrary(_T("*.dll"));
4) FuncVF = ::GetProcAddress(HDll, "Func_VF");
5) FuncVF(.);
6) ::FreeLibrary(HDll);


в VF:

FuncVF:
7) TlsIndex = TlsAlloc()
8) hThreadVF = ::CreateThread(ThreadVF,...)
9) ::WaitForSingleObject(hThreadVF,...)
10) TlsFree(TlsIndex)
(убирание 8) и 9) (!), или перенос 7) и 10) в ThreadVF ничего не меняет)

ThreadVF (расчет варианта задачи):
11) TlsSetValue(TlsIndex,.), TlsGetValue(TlsIndex), TlsSetValue(TlsIndex,.), TlsGetValue(TlsIndex), ...


Многократное обращение происходит к FuncVC.
Если бы не FuncVC_0, никаких TLS было бы не надо.
Автор: mr_eoi
Дата сообщения: 10.07.2005 19:58
Igorr
А кто мешает сделать переменную TlsIndex сделать глобальной и
Код: TlsIndex = TlsAlloc();
Автор: Igorr
Дата сообщения: 10.07.2005 20:05
mr_eoi

Цитата:
А кто мешает сделать переменную TlsIndex сделать глобальной


из MSDN:
TLS indexes are not valid across process boundaries. A DLL cannot assume that an index assigned in one process is valid in another process.

Автор: mr_eoi
Дата сообщения: 10.07.2005 20:29
Igorr

Код: TLS indexes are not valid across process boundaries. A DLL cannot assume that an index assigned in one process is valid in another process.
Автор: Igorr
Дата сообщения: 10.07.2005 20:38
mr_eoi
какой смысл в отдельной функции, если TlsAlloc() вызывается перед созданием hThreadVF - что аналогично отдельной функции.

Добавлено:

Цитата:
вызывай её сразу после загрузки DLL - всего один раз

так об этом и был самый первый пост - многократный вызов
Автор: mr_eoi
Дата сообщения: 10.07.2005 20:51
Igorr
А смысл в том, что вместо многократного вызова должен быть однократный, а как это обеспечить, зависит от тебя. Надоело тебе что-либо доказывать. В конце-концов, это у тебя проблема, а не у меня.
Автор: segeich
Дата сообщения: 10.07.2005 22:15
Igorr

Цитата:
Многократное обращение происходит к FuncVC.
Если бы не FuncVC_0, никаких TLS было бы не надо.

И что же такое FuncVC_0?

Приведенное тобою описания кода пока что никак не объясняет, зачем тебе TLS (TlsIndex локален внутри ThreadVF)


Цитата:
Цитата:А кто мешает сделать переменную TlsIndex сделать глобальной

из MSDN:
TLS indexes are not valid across process boundaries. A DLL cannot assume that an index assigned in one process is valid in another process.

А с чего ты взял, что глобальная переменная в DLL будет одна и таже для всех процессов, загрузивших эту DLL???
Автор: Igorr
Дата сообщения: 10.07.2005 22:31
segeich

Цитата:
зачем тебе TLS

а как можно еще пользовать функции и переменные из одной загруженной dll несколькими потоками одновременно?
Автор: segeich
Дата сообщения: 11.07.2005 01:20
Igorr
Если у тебя есть необходимость сохранять состояние (данные) между вызовами экспортируемых функции в рамках одного потока (или вызовом одной и той же ф-ции), но эти данные должны быть разными для разных потоков, то тогда TLS - то, что тебе нужно. Иначе и обычных переменных достаточно.

Пример:

Код:
// DLL
int Func()
{
static int N = 0;
return ++N;
}

// App thread #1
...
int x1 = Func();
int y1 = Func();

// App thread #2
...
int x2 = Func();
int y2 = Func();
Автор: OldGopher
Дата сообщения: 14.07.2005 23:10
segeich
TlsAlloc - создает зону памяти в 4 байта на тред, TlsFree = ее косит. Это понятно.

Непонятно, почему не используются функции TlsGetValue и TlsSetValue. Они-то достаточно быстрые...
Автор: segeich
Дата сообщения: 15.07.2005 00:31
OldGopher

Цитата:
Непонятно, почему не используются функции TlsGetValue и TlsSetValue. Они-то достаточно быстрые...

Я не совсем понял твой вопрос...
Автор: OldGopher
Дата сообщения: 15.07.2005 17:31
segeich
При инициализации DLL вызывает аллокатор, один раз. Это ясно. При деинициализации - деаллокатор. Это тоже ясно.

При инициализации треда должны вызываться функции рабаоты со значением TLS, а не с индексом. Индекс ведь не меняется весь период работы программы.
Что-то я тут зеваю...

Можно поподробнее о задаче? Что вообще надо хранить для каждого треда?
Автор: segeich
Дата сообщения: 15.07.2005 18:02
OldGopher
Просто я пытался убедить автора этого топика, Igorr, что ему совершенно не нужно TLS (исходя из того описания кода, что он здесь приводил). Глупо летать на самолете там, где и велосипеда достаточно.

Страницы: 1

Предыдущая тема: Delphi. Захват звука.


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.