AS>>To do
AS>>Поддержка MT.
CAM>Я не вижу проблемы с MT. Запись/чтение выравненного двойного слова атомарна, поэтому худшее, что может быть — лишний вызов GetProcAddress.
А я вижу. Читайте соотв. пост
CAM>Ещё у меня предложение — вместо разных макросов, для разных способов обработки ошибок позволить в макросе указывать функцию-обработчик, с таким же возвращаемым значенем, как и генерируемая функция. Таким образом будет выбор, или возвратить что-то инвалидное, или сделать throw / RaiseException. Кроме того, исчезнет зависимость от sprintf'а. Конечно, указывать в каждой функции обработчик ошибок — накладно, пока могу предложить только "глобальный" обработчик, который будет указываться в DL_USE_MODULE_BEGIN.
Политики удобнее. Это не только мое менение.
CAM>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.
Обрабатываются — вызывается соотв. политика ошибки. В ней есть доступ как к типу модуля, так и к типу функции, чего вполне досточно для формирования _любого_ сообщения об ошибке.
Здравствуйте, Andrew S, Вы писали:
AS>>>To do
AS>>>Поддержка MT.
CAM>>Я не вижу проблемы с MT. Запись/чтение выравненного двойного слова атомарна, поэтому худшее, что может быть — лишний вызов GetProcAddress.
AS>А я вижу. Читайте соотв. пост
Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.
CAM>>Ещё у меня предложение — вместо разных макросов, для разных способов обработки ошибок позволить в макросе указывать функцию-обработчик, с таким же возвращаемым значенем, как и генерируемая функция. Таким образом будет выбор, или возвратить что-то инвалидное, или сделать throw / RaiseException. Кроме того, исчезнет зависимость от sprintf'а. Конечно, указывать в каждой функции обработчик ошибок — накладно, пока могу предложить только "глобальный" обработчик, который будет указываться в DL_USE_MODULE_BEGIN.
AS>Политики удобнее. Это не только мое менение.
Во-первых, они у тебя "зашиты", поэтому толку от них — 0. Я как раз и предлагаю позволить их указывать в макросе. Потому-что я, например, не хочу ловить твой CDynFunException, или вообще, у меня EH отключен, и я хочу кинуть виндовое исключение.
Во-вторых, даже если ты их позволишь указывать, то функции будут удобнее, потому-что "объектность" политики, наличие у неё состояния, как у объекта — не нужно. Функции тут самое то. Кроме того, меньше писать.
Насчёт полезности политик — я согласен, но в данном случае они лишние.
CAM>>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.
AS>Обрабатываются — вызывается соотв. политика ошибки. В ней есть доступ как к типу модуля, так и к типу функции, чего вполне досточно для формирования _любого_ сообщения об ошибке.
Даа, _любое_ сообщение можно сформировать. Вот только в MakeReturn непонятно, _что_ не так — то ли LoadLibrary не удался, и GetModule().m_hModule вернула 0, то ли функция не найдена и GetProcAddress вернула 0.
...
CAM>>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.
AS>>Обрабатываются — вызывается соотв. политика ошибки. В ней есть доступ как к типу модуля, так и к типу функции, чего вполне досточно для формирования _любого_ сообщения об ошибке.
Блин, опять что-то забыл.
Я имел в виду, что, например, если dllка не найдена (т.е. CModule::m_hModule==0), то может потребоваться вообще показать мессадж бокс и завершиться.
Кстати, как насчёт переименовать CModule::GetModule() в CModule::GetInstance(), и добавить
CAM>Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.
Синглтон майерса не потокобезопасен. В данном случае он используется в CModule. Там можно немного и по-другому, но проблему это не снимет.
CAM>>>Ещё у меня предложение — вместо разных макросов, для разных способов обработки ошибок позволить в макросе CAM>Во-первых, они у тебя "зашиты", поэтому толку от них — 0. Я как раз и предлагаю позволить их указывать в макросе. Потому-что я, например, не хочу ловить твой CDynFunException, или вообще, у меня EH отключен, и я хочу кинуть виндовое исключение. CAM>Во-вторых, даже если ты их позволишь указывать, то функции будут удобнее, потому-что "объектность" политики, наличие у неё состояния, как у объекта — не нужно. Функции тут самое то. Кроме того, меньше писать.
CAM>Насчёт полезности политик — я согласен, но в данном случае они лишние.
Верно, насчет макроса, который позволит задавать политики, я как то забыл. Будет просто еще один макрос.
CAM>>>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.
AS>>Обрабатываются — вызывается соотв. политика ошибки. В ней есть доступ как к типу модуля, так и к типу функции, чего вполне досточно для формирования _любого_ сообщения об ошибке.
CAM>Даа, _любое_ сообщение можно сформировать. Вот только в MakeReturn непонятно, _что_ не так — то ли LoadLibrary не удался, и GetModule().m_hModule вернула 0, то ли функция не найдена и GetProcAddress вернула 0.
Анализируйте GetLastError(). Но я не думаю, что есть большая разница между ненахождение функции и незагрузкой модуля — технически это _одно_ неверное действие — невозможность отрезолвить функцию. Впрочем, вероятно, мысль сделать политики ошибки загрузки модуля тоже неплохая — если общественность поддержит, сделаю. Хотя, в этом случае будет возникать ситуация вызова аж 2-х политик в случае ошибки загрузки модуля, что на мой взгляд, неправильно. (технически это исправить несложно, но это возникает именно _логически_)
CAM>>?
CAM>>Мне кажется kernel::CModule::GetHandle() выглядит красивее, чем kernel::CModule().GetModule().m_hModule.
AS>Думаю, не стоит. Зачем посторонним доступ к хандлу модуля А вот сделать метод GetProcAddress и вызывать именно его — это то, что надо, на мой взгляд.
Я всё пытаюсь тебе сказать, что нужен способ узнать, что DLL не загрузилась. Если ты не хочешь сделать policy на этот случай — остаётся только проверка хэндла ручками. И по-моему, kernel::CModule::GetHandle() будет нагляднее.
Хотя даже сделай ты policy — всё равно нужно дать возможность проверять ручками, потому-что обрабатывать ошибку отсутствия DLLки скорее всего придётся штатно, в какой-нибудь InitInstance.
Здравствуйте, Andrew S, Вы писали:
CAM>>Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.
AS>Синглтон майерса не потокобезопасен. В данном случае он используется в CModule. Там можно немного и по-другому, но проблему это не снимет.
Синглтон майерса — умное слово. У тебя есть HMODULE, который суть void*, и есть функции его проверки и установки. Они атомарны. Худшее, что может быть, опять — последовательный вызов LoadLibrary.
...
AS>Анализируйте GetLastError(). Но я не думаю, что есть большая разница между ненахождение функции и незагрузкой модуля — технически это _одно_ неверное действие — невозможность отрезолвить функцию. Впрочем, вероятно, мысль сделать политики ошибки загрузки модуля тоже неплохая — если общественность поддержит, сделаю. Хотя, в этом случае будет возникать ситуация вызова аж 2-х политик в случае ошибки загрузки модуля, что на мой взгляд, неправильно. (технически это исправить несложно, но это возникает именно _логически_)
Возможно, ты прав, на счёт небольшой разницы этих двух ситуаций, однако по-моему предпочтительнее дать пользователям возможность решать, что для них важно и нужно. Когда есть возможность, ей можно и не пользоваться, а вот когда её нет, и она нужна, то возникают проблемы.
CAM>>>Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.
AS>>Синглтон майерса не потокобезопасен. В данном случае он используется в CModule. Там можно немного и по-другому, но проблему это не снимет.
CAM>Синглтон майерса — умное слово. У тебя есть HMODULE, который суть void*, и есть функции его проверки и установки. Они атомарны. Худшее, что может быть, опять — последовательный вызов LoadLibrary.
Ага, а регистрировать функцию для выполнения FreeLibrary (AtExit) вы будете ручками.
В общем, нет, все не то. Почитайте топик про синглтон майерса в форуме cpp и проникнитесь. До этого обсуждать что-либо про MT нет смысла.
AS>>Анализируйте GetLastError(). Но я не думаю, что есть большая разница между ненахождение функции и незагрузкой модуля — технически это _одно_ неверное действие — невозможность отрезолвить функцию. Впрочем, вероятно, мысль сделать политики ошибки загрузки модуля тоже неплохая — если общественность поддержит, сделаю. Хотя, в этом случае будет возникать ситуация вызова аж 2-х политик в случае ошибки загрузки модуля, что на мой взгляд, неправильно. (технически это исправить несложно, но это возникает именно _логически_)
CAM>Возможно, ты прав, на счёт небольшой разницы этих двух ситуаций, однако по-моему предпочтительнее дать пользователям возможность решать, что для них важно и нужно. Когда есть возможность, ей можно и не пользоваться, а вот когда её нет, и она нужна, то возникают проблемы.
НИКАКОЙ проблемы нет. Если m_hModule == 0 — значит, ошибка относится к загрузке модуля, иначе — к функции. Ну где здесь проблемы, не понимаю? Макрос, позволяющий задавать свою policy, я уже сделал.
__>Мне кажется в CNameId будет немного неправильные значения.
__>Решение 1 :
Если так написать, код просто не откомпилируется
error C2440: 'return' : cannot convert from 'unsigned short [13]' to 'const char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
Здравствуйте, Andrew S, Вы писали:
CAM>>>>Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.
AS>>>Синглтон майерса не потокобезопасен. В данном случае он используется в CModule. Там можно немного и по-другому, но проблему это не снимет.
CAM>>Синглтон майерса — умное слово. У тебя есть HMODULE, который суть void*, и есть функции его проверки и установки. Они атомарны. Худшее, что может быть, опять — последовательный вызов LoadLibrary.
AS>Ага, а регистрировать функцию для выполнения FreeLibrary (AtExit) вы будете ручками. AS>В общем, нет, все не то. Почитайте топик про синглтон майерса в форуме cpp и проникнитесь. До этого обсуждать что-либо про MT нет смысла.
Фу, как позорно облажался !
Хотя, зная, что такое синглтон майерса, я бы сделал так :
И по прежнему этот вариант лучше, чем любой с CriticalSection/Mutex'ами.
....
CAM>>Возможно, ты прав, на счёт небольшой разницы этих двух ситуаций, однако по-моему предпочтительнее дать пользователям возможность решать, что для них важно и нужно. Когда есть возможность, ей можно и не пользоваться, а вот когда её нет, и она нужна, то возникают проблемы.
AS>НИКАКОЙ проблемы нет. Если m_hModule == 0 — значит, ошибка относится к загрузке модуля, иначе — к функции. Ну где здесь проблемы, не понимаю? Макрос, позволяющий задавать свою policy, я уже сделал.
__>>Мне кажется в CNameId будет немного неправильные значения.
__>>Решение 1 :
AS>Если так написать, код просто не откомпилируется AS>
AS>error C2440: 'return' : cannot convert from 'unsigned short [13]' to 'const char *'
AS> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
AS>
CAM>И по прежнему этот вариант лучше, чем любой с CriticalSection/Mutex'ами.
И опять мимо.
Вот в этом месте
static Destroyer destroyer;
будет вызван конструктор Destroyer, но не только — еще и будет зарегистрирован деструктор дестроера. Причем вызывать или нет саму процедуру регистрации деструктора определяется состоянием флага.
Проще показать нап примере. На самом деле, этот код эквивалентен примерно такому:
static char destroyer[sizeof(destroyer)];
if (!instance_flag)
{
new (&destroyer[0])Destroyer();
atexit(destroyer_instance_deleter);
}
Думаю, дальше объяснять не надо. В общем — читайте Александреску, там про эти проблемы подробно.Ну и + форум, конечно.
PS MT я уже сделал, немного потестирую и выложу
Здравствуйте, CAMAD, Вы писали:
CAM>Худшее, что может быть, опять — последовательный вызов LoadLibrary.
Тогда нужен будет и лишний вызов FreeLibrary. Иначе — утечка.
Можно сделать тупо на атомарных функциях:
if (!m_hModule)
{
HMODULE hModule = ::LoadLibrary(...);
if (::InterlockedCompareExchangePointer(&m_hModule, hModule, NULL))
{
// Somebody did it already
::FreeLibrary(hModule);
}
}
Здравствуйте, Andrew S, Вы писали:
__>>Стоит доработать это.
AS>Зачем? Все правильно. В юникодном проекте строка с L откомпилится вполне нормально.
Вы меня не поняли.
Есть 4 ситуации —
не юникод проект . не юникодная строка — будет работать нормально
не юникод проект . юникодная строка — не будет работать
юникод проект . не юникодная строка — не будет работать
юникод проект . юникодная строка — будет работать нормально
Не, я понял.
__>не юникод проект . юникодная строка — не будет работать __>юникод проект . не юникодная строка — не будет работать
Вот эти 2 ситуации на мой взгляд могут присутствовать в 0.0001% случае и должны быть отправлены в dev\null
Это примерно как вызвать LoadLibrary в неюникодном проекте с юникодной строкой и возмущаться — почему это не компилируется
AS>будет вызван конструктор Destroyer, но не только — еще и будет зарегистрирован деструктор дестроера. Причем вызывать или нет саму процедуру регистрации деструктора определяется состоянием флага.
Мда, лучше бы мне подумать, прежде чем писать half-baked решение.
Мало того, что два раза может быть вызван ~Destroyer (это ты имел в виду ?), так ещё и FreeLibrary нужно вызывать для каждого LoadLibrary... Кстати, там Павел Блудов предложил решение второй проблемы, на Interlocked функциях — если и в деструкторе Destroyer сделать то же, т.е. менять хенлд с 0, и потом его грохать, то вроде всё должно быть ок (наконец-то !).
CAM>Мда, лучше бы мне подумать, прежде чем писать half-baked решение. CAM>Мало того, что два раза может быть вызван ~Destroyer (это ты имел в виду ?), так ещё и FreeLibrary нужно вызывать для каждого LoadLibrary... Кстати, там Павел Блудов предложил решение второй проблемы, на Interlocked функциях — если и в деструкторе Destroyer сделать то же, т.е. менять хенлд с 0, и потом его грохать, то вроде всё должно быть ок (наконец-то !).
Я видел, это все очевидно. Но зачем — когда на тех же Interlocked легко делается LW mutex и все проблемы идут лесом буквально 3-мя строчками кода
Добавлена поддержка MT. Отключается определением макроса DL_NO_MT.
Немного изменен интерфейс модуля
Добавлен макрос, позволяющий задавать custom policy для функций
Автоматическая поддержка юникода на основе макросов хедера от статически линкуемой библиотеки
Мелкие багфиксы
To do
Багфиксы
Уменьшение размера прокси в MT варианте
Что то еще?
По поводу MT — реализация, на мой взгляд, достаточно спорная, можно и нужно обсуждать.
Особенно это касается результирующих размеров прокси — в MT варианте 230-240 байт на функцию,
в ST порядка 80-90 (там все инлайнится буквально в plain code). В MT остается таки один
уровень не инлайновости, но это не спасает — все-таки 240 байт на функцию это прилично.
Конечно, думаю, не больше, чем у других, но все-таки значительно больше ST варианта.
Мысли?
Здравствуйте, Andrew S, Вы писали:
AS>Не, я понял.
__>>не юникод проект . юникодная строка — не будет работать __>>юникод проект . не юникодная строка — не будет работать
AS>Вот эти 2 ситуации на мой взгляд могут присутствовать в 0.0001% случае и должны быть отправлены в dev\null AS>Это примерно как вызвать LoadLibrary в неюникодном проекте с юникодной строкой и возмущаться — почему это не компилируется
Ну для этого LoadLibraryA есть
Предусмотреть все возможные проблемы заранее надо, или тогда написать чтобы не делать такое