Потокобезопаность SHGetFileInfo
От: Barbar1an Украина  
Дата: 14.07.19 14:10
Оценка:
SHGetFileInfo иногда не возвращает индекс иконок, особенно в релизном билде и при старте, после запуска глюков вроде нет

вызываю так

SHFILEINFOW sfi
CoInitialize(NULL);
SHGetFileInfo(path.c_str(), 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX);

причем вызываю в куче потоков сразу, т.е. вызывается одновременно много SHGetFileInfo

SHGetFileInfo работает с какимто своим внутренним ImageList'ом, а он вообще потокобезопасный?
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re: Потокобезопаность SHGetFileInfo
От: Pavel Dvorkin Россия  
Дата: 14.07.19 14:19
Оценка: 6 (1) +1
Здравствуйте, Barbar1an, Вы писали:


B>SHGetFileInfo работает с какимто своим внутренним ImageList'ом, а он вообще потокобезопасный?


Утверждают, что нет, правда, без пруфа

The other point to make is that SHGetFileInfo is not threadsafe. If you have multiple threads that call SHGetFileInfo then you will need to serialize those calls to SHGetFileInfo.

https://stackoverflow.com/questions/22102858/shgetfileinfo-returns-default-icon-from-background-thread-but-correct-icon-from
With best regards
Pavel Dvorkin
Re[2]: Потокобезопаность SHGetFileInfo
От: Barbar1an Украина  
Дата: 14.07.19 14:26
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Barbar1an, Вы писали:



B>>SHGetFileInfo работает с какимто своим внутренним ImageList'ом, а он вообще потокобезопасный?


PD>Утверждают, что нет, правда, без пруфа


PD>The other point to make is that SHGetFileInfo is not threadsafe. If you have multiple threads that call SHGetFileInfo then you will need to serialize those calls to SHGetFileInfo.


PD>https://stackoverflow.com/questions/22102858/shgetfileinfo-returns-default-icon-from-background-thread-but-correct-icon-from


пасиба но там нет ссылки на официальный док поэтому всё равно хз безопасная она или нет

кста проблема ВРОДЕ решилась вот с помощью такого порно:

    
for(int i=0; i<100; i++)
{
    SHGetFileInfo(path.c_str(), 0, &j->Sfi, sizeof(j->Sfi), SHGFI_SYSICONINDEX);
    if(j->Sfi.iIcon >= 0)
    {
        break;;
    }
    else
        Sleep(1);
}
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Отредактировано 14.07.2019 14:27 Barbar1an . Предыдущая версия .
Re[3]: Потокобезопаность SHGetFileInfo
От: Pavel Dvorkin Россия  
Дата: 15.07.19 02:45
Оценка:
Здравствуйте, Barbar1an, Вы писали:


B>кста проблема ВРОДЕ решилась вот с помощью такого порно:


ИМХО рискованное решение. Если функция все же не потокобезопасна и однажды будет одновременно вызвана и испортит какую-то внутреннюю структуру, то хорошего будет мало.
Что мешает для надежности поставить все под mutex ? Работы тут немного.
With best regards
Pavel Dvorkin
Re[4]: Потокобезопаность SHGetFileInfo
От: Barbar1an Украина  
Дата: 15.07.19 08:36
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Barbar1an, Вы писали:



B>>кста проблема ВРОДЕ решилась вот с помощью такого порно:


PD>ИМХО рискованное решение. Если функция все же не потокобезопасна и однажды будет одновременно вызвана и испортит какую-то внутреннюю структуру, то хорошего будет мало.

PD>Что мешает для надежности поставить все под mutex ? Работы тут немного.

согласен, но у иеня весь поток и состоит из этого вызова и если делать синхнонность, то мутекс уже не нужен, придется оставить тока один и сделать очередь
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re[5]: Потокобезопаность SHGetFileInfo
От: Pavel Dvorkin Россия  
Дата: 15.07.19 08:42
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>согласен, но у иеня весь поток и состоит из этого вызова и если делать синхнонность, то мутекс уже не нужен, придется оставить тока один и сделать очередь


Тогда не понял — о какой потокобезопасности может идти речь, если все в одном потоке ?
Или имеется в виду, что много потоков на базе одной функции потока ? Тогда EnterCriticalSection и все дела.
With best regards
Pavel Dvorkin
Re[6]: Потокобезопаность SHGetFileInfo
От: Barbar1an Украина  
Дата: 15.07.19 08:48
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Barbar1an, Вы писали:


B>>согласен, но у иеня весь поток и состоит из этого вызова и если делать синхнонность, то мутекс уже не нужен, придется оставить тока один и сделать очередь


PD>Тогда не понял — о какой потокобезопасности может идти речь, если все в одном потоке ?

PD>Или имеется в виду, что много потоков на базе одной функции потока ? Тогда EnterCriticalSection и все дела.

имеется ввиду что мои потоки которые исполоьзуюбт SHGetFileInfo сотоят из 2х строчек

{
CoInitialize(NULL);
SHGetFileInfo(path.c_str(), 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX);
}

и если мы повесим сюда мютекс, то в один момент работать будет тока один поток, что означает бессмысленность всей этой многопоточности и проще тогда сделать один поток для SHGetFileInfo в котором все SHGetFileInfo будут вызываться по очереди
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re[7]: Потокобезопаность SHGetFileInfo
От: Mystic Artifact  
Дата: 15.07.19 09:35
Оценка: 8 (2) +1
Здравствуйте, Barbar1an, Вы писали:

Вот тебе ещё немного пищи для размышлений из processhacker:

    // This no longer uses SHGetFileInfo because it is *very* slow and causes many other DLLs to be
    // loaded, increasing memory usage. The worst thing about it, however, is that it is horribly
    // incompatible with multi-threading. The first time it is called, it tries to perform some
    // one-time initialization. It guards this with a lock, but when multiple threads try to call
    // the function at the same time, instead of waiting for initialization to finish it simply
    // fails the other threads.


Собственно, как я понимаю, хуже всего ещё, что, эта кухня зависит от всяких экстеншонов к эксплореру, потому и проявляться может по разному.
Re[7]: Потокобезопаность SHGetFileInfo
От: Pavel Dvorkin Россия  
Дата: 15.07.19 10:36
Оценка: +1
Здравствуйте, Barbar1an, Вы писали:

B>имеется ввиду что мои потоки которые исполоьзуюбт SHGetFileInfo сотоят из 2х строчек


Понятно, но тогда тем более ты рискуешь. Ты фактически хочешь вызывать в многопоточном варианте функцию, потокобезопасность которой не гарантирована, и проверяешь, успешно она сработала или нет, по if(j->Sfi.iIcon >= 0).

Успешно или нет — вопрос сейчас второй, а вот если однажды два ее одновременных вызова в разных потоках что-то сломают, то будет уже не до успешности получения иконки

А если она не потокобезопасна, то черт знает, что может произойти, когда во время ее работы ее из другого потока вызывают. Может, если она делает часть A, то ничего страшного, а если часть B — то намного хуже.
With best regards
Pavel Dvorkin
Re[7]: Потокобезопаность SHGetFileInfo
От: Mystic Artifact  
Дата: 15.07.19 11:34
Оценка:
Здравствуйте, Barbar1an, Вы писали:

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

Ну, я бы еще проверил, на всякий случай, что основной поток у тебя в STA, используются comctl6, возможно руками вызвать инит, ну и возможно первый разок дернуть эту функцию (SH***it) из основного потока / или даже фонового, но один раз.

И когда это уже все соблюдено — пытаться ломиться к ней из разных потоков.
Re[8]: Потокобезопаность SHGetFileInfo
От: Mystic Artifact  
Дата: 15.07.19 11:50
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Понятно, но тогда тем более ты рискуешь. Ты фактически хочешь вызывать в многопоточном варианте функцию, потокобезопасность которой не гарантирована, и проверяешь, успешно она сработала или нет, по if(j->Sfi.iIcon >= 0).


Потокобезопасность в данном случае непонятное понятие. MSDN вещает:

You should call this function from a background thread. Failure to do so could cause the UI to stop responding.


You must initialize Component Object Model (COM) with CoInitialize or OleInitialize prior to calling SHGetFileInfo.


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

В целом, я делаю ставку на инициализацию, которой не хватает на основном потоке, из-за чего объект какой-то возможно умирает по завершении своего потока, например, или еще чего.

Конечно, это только предположение.

Просто сериализовать все вызовы на один фоновый поток — это так же можно расценивать как нарушение потокобезопасности, если какая-то "гыдота" внутри хочет доступа из основного потока. Но, честно говоря, думаю, там все более-менее нормально, просто как правильно использовать этот апи — неясно.
Re[9]: Потокобезопаность SHGetFileInfo
От: Pavel Dvorkin Россия  
Дата: 15.07.19 12:56
Оценка: 3 (1)
Здравствуйте, Mystic Artifact, Вы писали:


MA> Потокобезопасность в данном случае непонятное понятие. MSDN вещает:


MA>

You should call this function from a background thread. Failure to do so could cause the UI to stop responding.


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

MA>

You must initialize Component Object Model (COM) with CoInitialize or OleInitialize prior to calling SHGetFileInfo.


Это очевидно.

MA>Рекомандация выполнения в фоновом потоке уже само собой подразумевает у нормальных людей конкурентный доступ, так как в общем случае иного гарантировать уже нельзя. (Эти функции потенциально могут вызываться плагинами, внедренными DLL.)


А вот это нет. Фоновый поток — это не значит, что их можно запустить много, и из каждого конкурентно вызывать. Не вызывайте из UI-потока — вот и все, что тут сказано.
Например, написал ты самописную встроенную БД, и не предусмотрел в этой БД параллельных запросов. Запросы к ней из UI-потока делать нельзя, из фонового можно, но только из одного. В очередь, так сказать.


MA> Просто сериализовать все вызовы на один фоновый поток — это так же можно расценивать как нарушение потокобезопасности, если какая-то "гыдота" внутри хочет доступа из основного потока.


Кто такая "гыдота" — я не знаю, но если она захочет эту же функцию вызвать — да, неприятности возможны.

Но, честно говоря, думаю, там все более-менее нормально, просто как правильно использовать этот апи — неясно.

+1.
With best regards
Pavel Dvorkin
Re: Потокобезопаность SHGetFileInfo
От: Aniskin  
Дата: 15.07.19 19:36
Оценка: 5 (1)
Здравствуйте, Barbar1an, Вы писали:

А вызов FileIconInit при инициализации приложения не поможет?
Re[2]: Потокобезопаность SHGetFileInfo
От: Barbar1an Украина  
Дата: 15.07.19 22:08
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>Здравствуйте, Barbar1an, Вы писали:


A>А вызов FileIconInit при инициализации приложения не поможет?


а у меня его ни в хедерах ни в shell32 напрямую нет (660 ординал кажется, или я неправильно его искал...)
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.