Как освободить локальную память потока под последующее использование?

Тема в разделе "WASM.BEGINNERS", создана пользователем amvoz, 4 май 2009.

  1. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Да, как?

    Друзья! Приветствую всех!
    Допустим, я хочу сохранить в локальной памяти потока значения регистро ESI и EDI.
    Тогда использую код

    Код (Text):
    1. ;запихиваю локальную память потока значения ESI и EDI
    2. call TlsAlloc
    3. ;Пусть TlsAlloc вернула значение  x
    4.  
    5. push ESI
    6. push EAX
    7. call TlsSetValue
    8.  
    9. call TlsAlloc
    10. push EDI
    11. push EAX
    12. call TlsSetValue
    13.  
    14. ;...некоторый код...
    15. ;а теперь достаю из локальной памяти потока положенные туда значения. Освободившиеся ячейки памяти
    16. ;(номера x и x+ 1) можно будет использовать по-новой
    17.  
    18. call TlsAlloc
    19. sub eax, 2
    20. push EAX
    21. call TlsGetValue
    22. ;cейчас в EAX сохранённое значение ESI
    23.  
    24. call TlsAlloc
    25. sub eax, 2
    26. push EAX
    27. call TlsGetValue
    28. ;cейчас в EAX сохранённое значение EDI
    29.  
    30. ;Теперь посмотрим на значение свободной ячейки
    31. call TlsAlloc
    32. ;это значение равно x+ 4!
    Вот, собственно, вопрос и заключается в том, как сделать, чтобы следующий вызов

    Код (Text):
    1. call TlsAlloc
    Давал значение x, а не x+ 4.
    ... Функция TlsFree? Не подоходит. Ведь читаем у Джефри Рихтера (глава 21)
    "Когда необходимость в TLS-области у всех потоков в процессе отпадет, вызовите TlsFree"

    В других источниках тоже говорится о целесообразности вызова TlsFree, если отпадает надобность
    TLS-области у ВСЕХ потоков.
    А у меня только у одного потока такая надобность отпадает
    Помогите, пожалуйста!
     
  2. g00r

    g00r New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2009
    Сообщения:
    20
    Каждый вызов TlsAlloc быдет возвращать адрес новой ячейки, потому-что эта функция пердназначена для того, чтобы резервировать новую ячейку. Зачем резервировать одну и ту же ячейку дважды?
     
  3. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Угу.
    Теперь вопрос:
    Я считал с некоторой ячейки значение x.
    Теперь я хочу положить в эту ячейку некоторое значение. Как?
     
  4. g00r

    g00r New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2009
    Сообщения:
    20
  5. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    В общем, быстрый пример:
    Код (Text):
    1. Глобальная инициализация, выполнять _только_ один раз:
    2.     call TlsAlloc
    3.     mov [g_index1], eax
    4.     call TlsAlloc
    5.     mov [g_index2], eax
    6.  
    7.  
    8. Теперь в любом потоке можно использовать аллоцированные индексы
    9. (т.е. индексы глобальны для процесса, а значения, получаемые\выставляемые
    10. по этим индексам — локальны (уникальны) для каждого потока):
    11.     push esi        ; сохраним esi
    12.     push [g_index1]
    13.     call TlsSetValue
    14.  
    15.     push 0xcafebabe ; сохраним что-нибудь другое под другим индексом
    16.     push [g_index2]
    17.     call TlsSetValue
    18.  
    19.     ...
    20.     push [g_index1]
    21.     call TlsGetValue
    22.  
    23.  
    24. Глобальная деинициальизация:
    25.     push [g_index1]
    26.     call TlsFree
    27.     push [g_index2]
    28.     call TlsFree
      
       
    Вот так не делай так ни в коем случае (ведь формально один не может заранее знать, что ему вернёт TlsAlloc):
    Код (Text):
    1. call TlsAlloc
    2. sub eax, 2
       

    Ничего не поделаешь здесь. Максимум — можно обнулить значение локальной переменной:
    Код (Text):
    1. push 0
    2. push [g_index1]
    3. call TlsSetValue
     
  6. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Спасибо. Просто я такой вот код
    Код (Text):
    1.     call TlsAlloc
    2.     mov [g_index1], eax
    в находимых мною примерах игнорировал. (И в своём коде не использовал ячейки памяти, только регистры.) Ибо рассуждал, что g_index1 находится в адресном пространстве всего процесса. Один поток положил туда значение, второй положил... И что же?

    Для одного потока [g_index1]== a, а для другого [g_index1]== b?

    Очень, знаете, ли странно. Впрочем, нет ни малейшего основния этому не верить. Тем более, после разъяснений. Надо пробовать
     
  7. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Не получилось у нас однозначно распознать последний пост... Так что на всякий случай подтвердим:

    Да, g_index1 в адресном пространстве процесса; магия не используется: для одного потока [g_index1]==a, для другого [g_index1]==a, для третьего же [g_index1]==a.
    [И это из-за того, что код 'g_index1 := TlsAlloc()' нужно выполнять только один раз — например, сразу после старта программы, до создания других потоков (или, во всяком случае, до того, как какой-либо поток вызовет TlsSetValue\TlsGetValue)].
     
  8. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Опять ничего не понял

    Чуть пониже

    ...Так значения по этим индексам уникальны для каждого потока или всё же для всех потоков одинаковы?
     
  9. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Отличная вышла путаница, разве нет?

    Переформулируем:
    Допустим, есть у нас 3 потока.
    Вызываем TlsAlloc (из любого одного потока) и получаем индекс == 0xaa.
    После этого из потока1 вызываем TlsSetValue(0xaa, 0x11), а из потока2 — TlsSetValue(0xaa, 0x22).
    Теперь смотрим, что вернёт TlsGetValue:
    поток1: TlsGetValue(0xaa) == 0x11
    поток2: TlsGetValue(0xaa) == 0x22
    поток3: TlsGetValue(0xaa) == 0 ; Начальное значение — ноль.
     
  10. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Ну, я так первоначально и понял.
    Спасибо. Пошёл ковыряться.
    ...Я ведь не приложение пишу, а api-функцию перехватываю. Там сложно всё!