
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.11] |
![]() |
|
Страницы: (16) « Первая ... 8 9 [10] 11 12 ... 15 16 все ( Перейти к последнему сообщению ) |
Сообщ.
#136
,
|
|
|
И кстати, не потому ли ты упомянул об этих исключениях, что они у тебя регулярно возникают? Вообще, так быть не должно. Это следствие неправильно написанного кода. Windows здесь генерит исключение, линукс бы тупо падал по segmentation fault. Но плохо одинаково. Я тебе показал классы, если ты их смотрел, в которых исключений при обращении к указателю не будет. |
Сообщ.
#137
,
|
|
|
Цитата Олег М @ И кстати, не потому ли ты упомянул об этих исключениях, что они у тебя регулярно возникают? Какое странное предположение. Тем более, что об исключительных ситуациях начал разговор именно ты. --- Возникают исключительные ситуации или нет, всё должно быть готово к их перехвату и получению диагностики. Цена ничтожная, а польза немалая. --- Ты же не выбрасываешь все иголки и нитки под предлогом того, в данный момент пуговицы не болтаются ? |
Сообщ.
#138
,
|
|
|
Цитата ЫукпШ @ Какое странное предположение. Тем более, что об исключительных ситуациях начал разговор именно ты. Во-первых, ты так и не ответил на вопрос - возникают ли у тебя исключения при обращении содержимому указателя, либо при операции delete? Насколько я понимаю, очень часто. Во-вторых, ничего странного в этом нет. Мне бы даже и в голову не пришло сказать, что исключения возникают везде. Они возникают только когда вызывается оператор throw. Оператор delete и разыменование указателя этого не делают. При таких случаях вызываются системные виндовские исключения, которые, если ты их не отлавливаешь в __try/__except, преобразуются компилятором и выглядят как обычные сишные исключения. Если ты не вызываешь такие исключения специально (есть такая методика, см Рихтера), это означает что у тебя где-то ошибка в коде - ты не проверяешь значение указателя на null, обращаешься к удалённому указателю и т.д. В твоём случае это, обращение к указателям, происходит потому что ты их не синхронизируешь в потоках. Т.е. у тебя там есть какие-то попытки, но они явно не работают. Думаю, у тебя так ещё куча утечек памяти. Как следствие всего этого. Я тебе написал код, который все эти проблемы решает - синхронизация, утечки памяти и т.д. Если б ты вместо того, чтоб втирать мне про какие-то пуговицы, удосужился прочитать его и, соответственно, исправить свой, тебе же было бы легче. |
Сообщ.
#139
,
|
|
|
Цитата Олег М @ Цитата ЫукпШ @ Какое странное предположение. Тем более, что об исключительных ситуациях начал разговор именно ты. Во-первых, ты так и не ответил на вопрос - возникают ли у тебя исключения при обращении содержимому указателя, либо при операции delete? Насколько я понимаю, очень часто. Ответ простой - никогда ещё я не получал исключений, когда использовал этот шаблонный класс в многопоточном приложении. Хотя если посмотреть на дату, класс написан буквально к этому обсуждению. Но прежде чем показывать исходник я конечно проверил, как это работает. --- Что касается перехвата исключений. Используя __try/__except действительно можно получить диагностику в виде контекста. Однако, перехватить любое исключение посредством try/catch тоже можно. Для этого у компилера от Микрософт существует ключ "/eha". В этом случае тоже будет использован SEH, только диагностики не получишь. Так что, если речь идёт о критике принятого решения, критиковать надо само наличие блоков try/catch, поскольку в этом случае исключение будет перехвачено, а диагностика получена не будет. --- Скучно разговаривать - откуда ты можешь знать про утечки памяти и исключения у меня ? Чтобы выяснить наличие утечек в данном случае нет необходимости проводить сложные исследования. Достаточно получить диагностику конструкторов/деструкторов создаваемых объектов. |
Сообщ.
#140
,
|
|
|
Цитата ЫукпШ @ Скучно разговаривать - откуда ты можешь знать про утечки памяти и исключения у меня ? Обычно по коду видно, где могут возникнуть проблемы, а где нет, даже без тестов. Кстати, пытаюсь сейчас переделать свои указатели под Windows, 32бит, vs2010. Там у меня тоже куча древних серверов, которые как раз и выдают подобные exceptions (если б падали, как в линуксе, уже давно бы починил). Не так просто, оказывается. |
Сообщ.
#141
,
|
|
|
Цитата Олег М @ Обычно по коду видно, где могут возникнуть проблемы, а где нет, даже без тестов. "Наука начинается с измерения".© Для программирования это значит, что самый верный способ - потрассировать, проверить, как работает. Добавлено Цитата Олег М @ Кстати, пытаюсь сейчас переделать свои указатели под Windows, 32бит, vs2010. Там у меня тоже куча древних серверов, которые как раз и выдают подобные exceptions Это как-же ? В Линуксе я никак не могу перехватить все исключения. Там нет SEH. Падение чего-то предполагает долгое и упорное исследование. Кроме того, Виндус некоторые ошибки иногда прощает, Линукс - нет. --- Для Виндуса делаем так: Выставляем флаг /eha. Окружаем, значит, все поточные функции блоками __try/__except с диагностикой. Если кто-то из них "верещит", начинаем работать. Можно по-ползать по памяти, изучая исполнимый код отладчиком, но это долго и муторно. Можно тупо ловить исключение блоками try/catch, уже без диагностики, по алгоритму "ловли льва в африке". Научное исследование превращается в примитивную и чисто техничекую работу. Не всегда конечно, но почти. |
Сообщ.
#142
,
|
|
|
Цитата ЫукпШ @ Падение чего-то предполагает долгое и упорное исследование. Кроме того, Виндус некоторые ошибки иногда прощает, Линукс - нет. Ну, чтоб понять что твой код будет падать, мне достаточно было беглого взгляда. На собеседованиях и то более сложные задачи предлагают. Это во–первых. Во–вторых, я вроде как говорил, что seh исключений в рогамме быть не должно, это сигнал о том, что у тебя ошибка в коде, твоя. В потоках никакие отладчики и никакие флаги тебе не помогут. Поможет лишь тупое разглядывание и анализ собственного кода. Если хочешь, я выложу виндовскии код указателей. Но при условии, что ты мне вызовешь там seh прерывание |
Сообщ.
#143
,
|
|
|
Цитата Олег М @ Ну, чтоб понять что твой код будет падать, мне достаточно было беглого взгляда. Т.е. собеседование ты провалил. Чтобы быть совсем уверенным, я встроил этот класс в своё приложение, которое должно работать 24 часа, 365 дней в году. Никаких исключений обнаружить не удалось. Добавлено Цитата Олег М @ В потоках никакие отладчики и никакие флаги тебе не помогут. Откуда ты знаешь ? Если возникнет исключение, я получу контекст, имя файла и стоку в исходниках, в которой производится вызов фильтра. Если я утверждаю это так определённо, то потому, что неоднократно это делал. --- Определить место, где произошло исключение можно достаточно легко. А вот понять "почему" - действительно не всегда просто. Это "да". Вот я взял, да и поделил на 0. Вот полученная диагностика: Цитата 00000017 23:39:42 [2476] FILE=.\biWth.cpp, Line=159 00000018 23:39:42 [2476] EXCEPTION_INT_DIVIDE_BY_ZERO, ExAddr=004132B6 00000019 23:39:42 [2476] CF =0001003F DR0=00000000 DR1=00000000 DR2=00000000 00000020 23:39:42 [2476] DR3=00000000 DR6=00000000 DR7=00000000 EAX=0000000A 00000021 23:39:42 [2476] EBX=00A1CC40 ECX=00000000 EDX=00000000 EBP=00E4FF68 00000022 23:39:42 [2476] EIP=004132B6 EDI=7C91043E ESI=00A1CC40 ESP=00E4FF14 00000023 23:39:42 [2476] EF =00010246 SCS=0000001B SDS=00000023 SFS=0000003B 00000024 23:39:42 [2476] SGS=00000000 SSS=00000023 SES=00000023 ...=00000000 Добавлено Цитата Олег М @ Если хочешь, я выложу виндовскии код указателей. Но при условии, что ты мне вызовешь там seh прерывание А зачем ? Сделай как в книге Рихтера. Внутри блока __try/__except подели на 0 или разименуй нулевой указатель. |
Сообщ.
#144
,
|
|
|
Цитата ЫукпШ @ Откуда ты знаешь ? Если возникнет исключение, я получу контекст, имя файла и стоку в исходниках, в которой производится вызов фильтра. Если я утверждаю это так определённо, то потому, что неоднократно это делал. Ну, ты мне так и не ответил, какие именно методы должны быть потокобезопасными. Думаю, что вот эти три: ShPtrIntLockedTh<T>::ShPtrIntLockedTh(const ShPtrIntLockedTh& p) ShPtrIntLockedTh<T>::DisConnect(void)/ShPtrIntLockedTh<T>::DisConnectSlave(void) ShPtrIntLockedTh<T>::operator=(const ShPtrIntLockedTh& p) Рассмотрим сценарий, когда один поток вызывает конструктор копирования, а другой ShPtrIntLockedTh<T>::DisConnect: 1-й: вызывает DisConnect(), потом DisConnectSlave(), который возвращает true 2-й: вызывает ShPtrIntLockedTh(const ShPtrIntLockedTh& p), проверяет p.StatPtr, который != null, делает StatPtr = p.StatPtr; 1-й: делает delete StatPtr 2-й: вызывает StatPtr->IncCount(); Т.е. пытается изменить удалённый объект В этом случае тебе повезёт, если в этой точке возникнет исключение. А так - последствия неопределённые, и ты ни одним отладчиком не сможешь найти причину. |
Сообщ.
#145
,
|
|
|
Цитата Олег М @ Потокобезопасный указатель означает, что мне не надо использовать дополнительных средств, ресурсов и блокировок при работе с этим классом. Это не от хорошей жизни, поверь. Поверю. Но не до конца. Окончательно поверю только данным профилировщика. Ты его запускал? ![]() ![]() Цитата Олег М @ Сервер, вернее один из серверов, - по сути просто кэширует данные, которые хранятся в базе данных и отдаёт их либо по rpc-запросу, либо по подписке клиенту. Данные в кэше обновляются асинхронно, по сигналам из базы. Ещё, по запросам выполняются ява-скрипты, которые получают данные из памяти сервера, делают какие-то вычисления и возвращают результат. Он не работает с браузеры, запросы идут от веб-серверов, по сокетам, TCP. Цитата Олег М @ У меня не лочатся списки подписчиков. Все нотификации выполняются асинхронно и независимо от других. Я не могу допустить, чтоб все клиенты блокировались из-за одного, либо чтоб данные перестали обновляться, из-за того, что какая-то процедура тормозит. Вернее, определённые блокировки есть, но в основном для того чтоб контролировать количество запущенных потоков. Цитата Олег М @ У меня не веб-сервис. 4000 (тут, признаюсь, немного приврал, такой цифры я не видел. В среднем - 3500) это коннекты по веб-сокетам, постоянные. RPC-коннекты я не считаю, но в среднем где-то один в секунду. Итак, java-скрипты, RPC, веб-сокеты, асинхронная работа с БД... Асинхронное оповещение через потоки означает пул потоков и очередь на отправку уведомлений в нём. Нет, определённо, шаренный указатель на клиента - это самое узкое место. ![]() ![]() Цитата Олег М @ Во-вторых, меня не беспокоит скорость подписки/отписки - куда ещё быстрее?. Это должно беспокоить тебя. А вот нужно ли быстрее? А если нужно, то в каком конкретно месте? Цитата Олег М @ У меня сервер работает на машине с 4 процессорами и 16Гб памяти. Хранит данные о 50тыс аккаунтов и 15тыс инструментов, постоянно обновляет их и рассылает подписчикам. Как ты думаешь у меня там есть возможность делать что-то не оптимально (хотя, конечно, косячу регулярно)? Есть. Возможность есть всегда. ![]() Но это я всё ёрничаю. На самом деле, не далее, как вчера, обсуждали с коллегой именно такой тип указателя, о котором ты говоришь. Но... Есть нюанс. Атомики при его реализации будут реальными спичками, ибо там (как я и описывал в своих предыдущих комментариях) вызов методов обёрнут лочкой, при смене указателя вызываются callback'и, есть wait-функции доступности, и прочие подобные вещи. Вот так вот неоптимально. ![]() |
Сообщ.
#146
,
|
|
|
Цитата Flex Ferrum @ Поверю. Но не до конца. Окончательно поверю только данным профилировщика. Ты его запускал? Пока же останусь при мнении, что экономия на блокировках при работе "с этим классом" - это экономия на спичках Нет, не запускал и не планирую. Что он мне может сказать, чего я и так не знаю? У меня нет проблем с производительностью и временем обработки запроса, которое в среднем ~0мс. Как ты правильно заметил, количество запросов и объёмы данных у меня не те, чтоб мне понадобилось то, что ты называешь "агрессивной оптимизацией". Тем более я слабо представляю, как можно профилировать сервер с кучей потоков и коннектов. Там в результатах нужно будет разбираться дольше. Основная проблема у меня - это надёжность и сопровождение. А то что ты называешь "спичками" уменьшает код в разы, соответственно повышает его сопровождаемость. Надёжность тоже, за счёт того что при разработке используется меньшее количество решении и нужно соблюдать меньшее количество правил. Цитата Flex Ferrum @ Нет, определённо, шаренный указатель на клиента - это самое узкое место. Ещё раз: профилировщик это подтвердил? Нет, не определённо. Ты свой код через профилировщик прогонял? Он подтвердил, что функция Unregister() у тебя будет самым слабым местом, при увеличении количества подписчиков? Цитата Flex Ferrum @ На самом деле, не далее, как вчера, обсуждали с коллегой именно такой тип указателя, о котором ты говоришь. Но... Есть нюанс. Атомики при его реализации будут реальными спичками, ибо там (как я и описывал в своих предыдущих комментариях) вызов методов обёрнут лочкой, при смене указателя вызываются callback'и, есть wait-функции доступности, и прочие подобные вещи. Вот так вот неоптимально. Вот за это спасибо. Хотелось бы послушать ваше обсуждение. Что-то я не понял, что ты имеешь ввиду под "спичками" - то ли что это зря потраченное время на оптимизацию, то ли это не оптимизирует работу, а наоборот? Цитата Flex Ferrum @ Да и вот сел сегодня, думаю, дай напишу этот самый "потокобезопасный" shared_pointer. Принялся интерфейс weak/shared_ptr'а проектировать, и понял, что ну нет смысла именно эту связку делать потокобезопасной. Не для того она предназначена. Задача shared_ptr сводится к тому, чтоб контролировать время жизни объекта, weak_ptr - чтобы быть в курсе жив объект или нет. Было бы здорово, если бы ты попытался написать его. |
Сообщ.
#147
,
|
|
|
Кх-гм... Почему-то представляется диалог:
- Доктор, я себя что-то неважно чувствую. - А, голубчик, у вас волчанка. - Доктор, с чего вы взяли? Вы ведь даже анализов у меня не взяли! - А у вас, вон, глаза красные. Примерно так выглядят разговоры об оптимизации кода без привлечения данных от инструментальных средств. ![]() А профилировать сервер просто: запускаешь его под профайлером, даёшь тестовую нагрузку нужного профиля и снимаешь данные. У тебя ведь есть тестовый стенд, и тестовый же генератор нагрузки? Оптимизация списка подписчиков, о которой я говорил, была сделана по результатам анализа логов и собранных статистических показателей работы системы - размеры очередей, количество входящих запросов, объёмы исходящих данных, креш-дампы, и т. п. А до этого, в предыдущем проекте - по результатам жёсткого профилирования, где всё крутилась в одном процессе, скорости были на порядки выше и данные снимались не только VTune'ом, но и с помощью Windows Performance Toolkit. Оптимизацией под контролем инструментальных средств я занимаюсь лет десять, а то и больше. На счёт указателя - есть подозрение, что он тебе не очень подойдёт. Там не будет "спичек" (в смысле, мелких оптимизаций, сделанных без видимой причины), зато будет rw-lock. Такая вот жирная пессимизация. ![]() Добавлено И это, в твоей задаче я не вижу именно shared_ptr. Ты не разделяешь владение своим объектом, не отправляешь копии указателя на него в "свободное" плаванье. Тебе нужен что-то в стиле RemoteObjectHolder. Это не столько указатель, сколько сервисный класс, контролирующий доступ к объекту из разных потоков, его операбельность и прочие подобные фишки. Ну, насколько я понял твою задачу. Ты не планируешь создавать копии этого холдера, ты предполагаешь работать только с одной из всех потоков. Так ведь? |
Сообщ.
#148
,
|
|
|
Цитата Flex Ferrum @ Примерно так выглядят разговоры об оптимизации кода без привлечения данных от инструментальных средств. И именно поэтому "предварительную оптимизацию" называют корнем всех зол - ведь можно потратить массу времени увлеченно оптимизируя то, что в этом совершенно не нуждается. Чаще я наблюдал другую проблему - люди с помощью кучи инструментальных средств пытаются найти ошибку или оптимизировать абсолютно дикий код. При этом ужасно гордятся тем, как они ловко пользуются этими средствами. Это касается и с++ и баз данных и прочего тоже. Цитата Flex Ferrum @ На счёт указателя - есть подозрение, что он тебе не очень подойдёт. Там не будет "спичек" (в смысле, мелких оптимизаций, сделанных без видимой причины), зато будет rw-lock. Такая вот жирная пессимизация. Где ты нашёл у меня rw-lock? Цитата Flex Ferrum @ И это, в твоей задаче я не вижу именно shared_ptr. Ты не разделяешь владение своим объектом, не отправляешь копии указателя на него в "свободное" плаванье. Тебе нужен что-то в стиле RemoteObjectHolder. Это не столько указатель, сколько сервисный класс, контролирующий доступ к объекту из разных потоков, его операбельность и прочие подобные фишки. Ну, насколько я понял твою задачу. Ты не планируешь создавать копии этого холдера, ты предполагаешь работать только с одной из всех потоков. Так ведь? Не очень понял, но наверное что-то типа того. Что RemoteObjectHolder делает, чего не умеет shared_ptr? |
Сообщ.
#149
,
|
|
|
Цитата Олег М @ Где ты нашёл у меня rw-lock? У тебя его нет. Он у меня будет. Цитата Олег М @ Не очень понял, но наверное что-то типа того. Что RemoteObjectHolder делает, чего не умеет shared_ptr? Самокопироваться, например. То есть интерфейс этого класса явно рассчитан на то, что один и тот же его экземпляр будут использовать в разных потоках. shared_ptr ориентирован на копирование с последующем независимым поведением каждой из копии (я это показывал в примере выше). Цитата Олег М @ Чаще я наблюдал другую проблему - люди с помощью кучи инструментальных средств пытаются найти ошибку или оптимизировать абсолютно дикий код. При этом ужасно гордятся тем, как они ловко пользуются этими средствами. Это касается и с++ и баз данных и прочего тоже. Ну, не знаю. Когда при мне занимались оптимизацией (и когда я сам в ней участвовал) задача была вписаться в те или иные требования по производительности и потребляемым при этом ресурсам. И ставилась она не в формулировках "давайте заоптимизируем вот этот кусок кода", а "видишь график распределения времени по функциям? Вот необходимо, чтобы вот эта, вот эта и вот та части занимали не больше 20% от общего времени работы системы". Или: "При 200 активных подключениях длительностью не менее полминуты и десяти новых подключениях в секунду объём потребления процессора не превышал 30%". Или: "При входящем траффике в 1Gb/sec время генерации исходящих событий не должно превышать 10 сек. при 80% потребления CPU". Как-то так. И от этого плясали. |
Сообщ.
#150
,
|
|
|
Цитата Flex Ferrum @ Кх-гм... Почему-то представляется диалог: - Доктор, я себя что-то неважно чувствую. Вообще, если ты не заметил, то я пришёл сюда не жаловаться на что либо. Я просил всего лишь оценить реализацию класса. Неважно зачем и как я его буду использовать. Но для того, чтобы принимать решения, мне нужно знать недостатки класса, его тонкие места. Чтобы пользоваться классом, нужно представлять, как он реализован. Я встречал людей, которые кричали, что C++ отстой, а C рулит и приводили пример как быстро работает массив int[100] по сравнению с std::vector. Добавлено Цитата Flex Ferrum @ У тебя его нет. Он у меня будет Именно поэтому я там и воспользовался счётчиком. Добавлено Цитата Flex Ferrum @ Самокопироваться, например. То есть интерфейс этого класса явно рассчитан на то, что один и тот же его экземпляр будут использовать в разных потоках. shared_ptr ориентирован на копирование с последующем независимым поведением каждой из копии (я это показывал в примере выше). Я слабо представляю, как operator-> можно использовать в разных потоках |