Тема: C++ haters handbook :-)

Ответить в теме
Страница 7 из 8 ПерваяПервая ... 5 6 7 8 ПоследняяПоследняя
Показано с 121 по 140 из 157
  1. Вверх #121
    Не покидает форум Аватар для Ull9
    Пол
    Мужской
    Адрес
    Мюнхен
    Сообщений
    19,028
    Репутация
    1490
    Почему бы ему этого не сделать?
    А если более реальный случай - коды двух описаний типов писали разные люди? Тогда програмиста вообще не колышет ошибка компилятора - это не его зона ответственности и он считает себя вправе применитьь явный кастинг. В жизни оно именно так и происходит - сам видел.

    I ja videl javnyj cast. nu i kakoj ty delaesh' vyvod?
    ja delaju takoj, cast, ljuboj est' priznak plohogo design (99%). nedarom v c++ on vygladit tak chtob ego mozhno bylo najti (static_cast<>...)
    eshhe odin primer kak C stil' programmirovanija, a imenno cast, est' zlo. i priznak plohogo koda.


  2. Вверх #122
    Не покидает форум Аватар для Ull9
    Пол
    Мужской
    Адрес
    Мюнхен
    Сообщений
    19,028
    Репутация
    1490
    Т.е. здесь С даже строже, чем С++ - нет скрытых преобразований при наследовании.
    -----

    ne ponjal
    pochemu on strozhe?
    kakie u c++ skrytye preobrazovanija?
    kakoe nasledovanie v C?
    davaj o terminah, chto ty ponimaesh' pod nasledovaniem?
    dlja menja nasledovanija v C net. ili u tebja kakoe to svoe ponjatie o nasledovanii?

  3. Вверх #123
    Не покидает форум Аватар для Ull9
    Пол
    Мужской
    Адрес
    Мюнхен
    Сообщений
    19,028
    Репутация
    1490
    Уровней наследования всего 2 и ошибки в коде типа

    typedef void* type1_t;
    typedef void* type2_t;
    int type1_func(type1_t x);
    ...
    type2_t y;
    type1_func(y);

    ошибки видны визуально сразу.
    ---------------------------
    jeto esli oni v sosednih strokah. a v real'noj zhizni oni mogut byt' voobshhe v raznyh fajlah!
    chto i bylo u nas v logginge.

    Nu zachem jetot gemorr kogda C++ GARANTIRUET ih otsutstvie?

  4. Вверх #124
    Не покидает форум Аватар для Ull9
    Пол
    Мужской
    Адрес
    Мюнхен
    Сообщений
    19,028
    Репутация
    1490
    privedennyj kod dlja poslednego varianta dog.
    ne zanju kak drugim, no chitat' kod na C mozhno, no vygljadit on bolee urodlivej.
    pri uslozhnenii primerov. (chem naverno zanimatsja nam i ne nado bolshe).
    ochevidno, chto chitaemost' koda tol'ko uhudshaetsja.

  5. Вверх #125
    Постоялец форума Аватар для Guffy
    Пол
    Мужской
    Адрес
    Одесса
    Возраст
    51
    Сообщений
    1,356
    Репутация
    256
    Цитата Сообщение от homo ludens Посмотреть сообщение
    А ты не убивайся.
    Код:
    int bar(int lenght, char* a, char* b, char* c)
    {
    	return 0;
    }
    
    int fooC(int lenght)
    {
    	char* a=alloca(length);
    	char* b=alloca(length);
    	char* c=alloca(length);
            return (a && b && c) ? bar(lenght, a, b, c) : -1;
    }
    вообще fooC можно в одну строку написать, но лениво.
    это вы мне будете в детском саду рассказывать и про alloca и про 1мб стека на поток (в винде по умолчанию)
    а насчет ansi C, если я правильно помню, то так нельзя
    Код:
    int fooC(int lenght)
    {
    	char* a=alloca(length);
    	char* b=alloca(length);
    	char* c=alloca(length);
            return (a && b && c) ? bar(lenght, a, b, c) : -1;
    }
    можно так
    Код:
    int fooC(int lenght)
    {
    	char* a;
    	char* b;
    	char* c;
    
    	a=alloca(length);
    	b=alloca(length);
    	c=alloca(length);
            return (a && b && c) ? bar(lenght, a, b, c) : -1;
    }
    зы: в одну строчку и я писать умею, особенно если наплевать на правила хорошего тона в форматировании кода
    Последний раз редактировалось Guffy; 09.05.2007 в 20:04.

  6. Вверх #126
    Постоялец форума Аватар для Guffy
    Пол
    Мужской
    Адрес
    Одесса
    Возраст
    51
    Сообщений
    1,356
    Репутация
    256
    Второе, за шо я "повбывав бы", так вот таки за эти void*
    Уже не времена, когда достаточно, текстового редактора и компилятора.
    Нормальный разработчик, когда не клепает примеры на коленке, а работает с проектом, использует IDE и отладчик визуальный.
    И что вы увидите в отладчике, когда по программе гуляют void* указатели?
    Адрес указателя и хрен с маслом. Каждый раз кастовать в watch? мазохизм.
    А по типизированным указателям все ясно видно.
    Да, я такой. Я люблю мягкое кресло и теплые тапочки

  7. Вверх #127
    Частый гость Аватар для homo ludens
    Пол
    Мужской
    Сообщений
    751
    Репутация
    141
    блин, пока сидел в работе набежало много постов...

    по порядку.
    pimpl - неважно, приватные члены или нет - при любом их изменении возникает перекомпиляция, так как они занимают место. Перекомпиляция возникает и при смене методов класса, но - методы класса всегда более стабильны чем члены.
    Выход - переместить их в приватный класс и реализовать pimpl без членовы класса, любых - приватных или публичных, заменив акцессорами.
    Если же pimpl-класс без членов, то он решает те же задачи, что и интерфейс, а тогда нафиг он нужен? Интерфейс намного гибче и расширяемей.

    По поводу void* - блин, единственная дырка в типизации это возможность преобразования без каста из void* в указатель. Опять таки, полезно это или вредно - я не скажу. Мне это не мешает, но наверное есть пуритане, которым это не нравится. Я не молюсь на строгую типизацию и я не верю страшилкам, рассказываемым студентам, о том, что любое нарушение сохранности - абсолютное зло. Я знаю, что языки без сохранности типов позволяют намного более скоростную разработку программ, но на больших объемах кода дают дополнительный рост глюков. Нет здесь однозначного решения. Если бы оно было - запретили бы явные касты нафиг, но мне кажется, что такие языки нежизнеспособны.

    Для меня возможность безкастового преобразования - просто синтаксический сахар. Примеры ошибок связанные с ними есть, но наверное можно накопать попытки взятия квадратного корня из HWND. Основные проблемы не здесь и не эта точка - самая болезненная в языках программирования.

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

    Как воид* провоцирует подход по двойному объявлению типов - мне непонятно. Имхо программисту - программистово а архитектору - архитекторово. И код написанный программером должен обязательно читаться кем-то другим, хотя бы его напарником (если речь идет об XP). А уж не проверять интерфейсы, где двойное объявление видно сразу - гарантия проблем. Если уж на то пошло, то вещи на которые провоцирует С++ намного хуже - то же самое избыточное наследование например.
    Вообще partially weak type в С обсуждалось до нас годами и будет обсуждаться после нас с достаточно вескими аргументами с обоих сторон. Я подозреваю, что мы сейчас просто повторяем какой-то из бесчисленных диалогов в инете.
    Кроме того избежать безкастового приведения в интерфейсах, (где typedef void* используется чаще всего) можно, просто никто так не делает, причем не по причине дурного тона, а потому что нет смысла - очень мала вероятность такой ошибки.
    Кроме void* как абстрактный тип часто используется int в качестве хендла и пришлось бы резать и его, на всякий случай - вдруг кто-то сложит два файловых дескриптора, а потом передаст аргумент функции удаления потока. Я пока таких случаев не встречал, но вдруг...

    По поводу уродливого кода - тут конечно на любителя. Мне например запись итератора кажется уродливой. Кроме того самый уродливый код и самые красивые решения я видел на http://www.ioccc.org/
    Одна операционка в 32 Кб чего стоит.
    Код программы, печатающий собственный текст (без доступа к сырцу) всегда выглядит уродливо, но эту простую программку оказывается не все выпускники могут написать.

    по поводу примера кода - там надо переработать и С++ код под интерфейсы. Иначе несправедливо выйдет - С код будет решать другие задачи - более широкие. Тот пример, что я дал - нехороший и так писать конечно нельзя.
    Если есть время и настроение - можем сделать сравнение - ты свою реализацию на С++ я свою на С. Они конечно будут здоровыми и в пост не влезут. У меня на С 4 файла - два стабильных, с гарантией, что они не меняются никогда при любом дизайне и два - определяемых пользователем Isound/cat/dog. На С++ можно сделать в 3.
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  8. Вверх #128
    Частый гость Аватар для homo ludens
    Пол
    Мужской
    Сообщений
    751
    Репутация
    141
    Цитата Сообщение от Guffy Посмотреть сообщение
    это вы мне будете в детском саду рассказывать и про alloca и про 1мб стека на поток (в винде по умолчанию)
    Тогда не надо пользоваться динамическими переменными и аргументами функций.
    В том примере параметры не использовались для создания объекта, т.е. удовлетворяли всем требованиям автоматических переменных. Я так их и реализовал, в GNU диалекте можно было бы написать и так.
    Код:
    int fooC(int lenght)
    {
    	char a[length];
    	char b[length];
    	char c[length];
            return bar(lenght, a, b, c);
    }
    Цитата Сообщение от Guffy Посмотреть сообщение
    а насчет ansi C, если я правильно помню, то так нельзя
    можно.
    http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf
    п. 6.7.8

    Цитата Сообщение от Guffy Посмотреть сообщение
    зы: в одну строчку и я писать умею, особенно если наплевать на правила хорошего тона в форматировании кода
    Правила хорошего тона в программировании называются coding style.
    Я пользуюсь этим
    http://www.gnu.org/prep/standards/standards.html
    и немного
    Linux kernel coding style (в любом ядре линукса есть файл с описанием)
    Все, что там есть по этому поводу - ограничение длины строки и ограничение размера функции. Я их выполнил.
    Вообще высокий уровень вложенности - это то, что отличает С-подобный синтаксис от бейсико-подобного, а оба этих синтаксиса покрывают большинство индустриальных языков.

    Цитата Сообщение от Guffy Посмотреть сообщение
    Второе, за шо я "повбывав бы", так вот таки за эти void*
    Уже не времена, когда достаточно, текстового редактора и компилятора.
    Нормальный разработчик, когда не клепает примеры на коленке, а работает с проектом, использует IDE и отладчик визуальный.
    Ну, последний раз я пользовался отладчиком даже не помню сколько лет назад. А уж IDE - на удаленном хосте или на машине заказчика...
    Так что тут ничего не могу сказать.
    Цитата Сообщение от Guffy Посмотреть сообщение
    И что вы увидите в отладчике, когда по программе гуляют void* указатели?
    А уж что вы увидите в отладчике отлаживая недетерминированный код... Наверное год рождения моей бабушки.
    И сильно в мультитриде отладчик помогает?
    Цитата Сообщение от Guffy Посмотреть сообщение
    Да, я такой. Я люблю мягкое кресло и теплые тапочки
    Я тоже люблю теплые тапочки, только вот когда по болоту идти надо - предпочитаю сапоги. А по болоту часто ходить приходится...

    Имхо техника программирования, когда кодер вместо того чтобы продумать кусок кода а потом написать - гоняет цикл do {написал-запустил-посмотрел watch-исправил} while (watch переменная несовпадает с ожидаемой) дает намного больше глюков, чем любой void*.
    Плюс непотопляемую уверенность в правильности этого куска кода и что виноват в глюке кто-то другой...
    Однопоточные программы ушли, сейчас век недетерминированного кода...
    Раньше было все проще...
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  9. Вверх #129
    Частый гость Аватар для homo ludens
    Пол
    Мужской
    Сообщений
    751
    Репутация
    141

    уродливый код
    Код:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    #define _			;double
    #define void			x,x
    #define case(break,default)	break[O]:default[O]:
    #define switch(bool) 		;for(;x<bool;
    #define do(if,else)		inIine(else)>int##if?
    #define true			(--void++)
    #define false			(++void--)
    
    char*O=" <60>!?\\\n"_ doubIe[010]_ int0,int1 _ Iong=0 _ inIine(int eIse){int
    O1O=!O _ l=!O;for(;O1O<010;++O1O)l+=(O1O[doubIe]*pow(eIse,O1O));return l;}int
    main(int booI,char*eIse[]){int I=1,x=-*O;if(eIse){for(;I<010+1;I++)I[doubIe-1]
    =booI>I?atof(I[eIse]):!O switch(*O)x++)abs(inIine(x))>Iong&&(Iong=abs(inIine(x
    )));int1=Iong;main(-*O>>1,0);}else{if(booI<*O>>1){int0=int1;int1=int0-2*Iong/0
    [O]switch(5[O]))putchar(x-*O?(int0>=inIine(x)&&do(1,x)do(0,true)do(0,false)
    case(2,1)do(1,true)do(0,false)6[O]case(-3,6)do(0,false)6[O]-3[O]:do(1,false)
    case(5,4)x?booI?0:6[O]:7[O])+*O:8[O]),x++;main(++booI,0);}}}
    рисует график полиномиальной функции - коэффициенты в командной строке (например 0 0 1 нарисует параболу).
    Взято с http://www.de.ioccc.org/whowon.html
    Понятно, что игрушка, только вот на С++ я такого не видел...
    Код операционной системы сюда постить не буду - там целых 166 строк кода...
    Последний раз редактировалось homo ludens; 10.05.2007 в 21:50.
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  10. Вверх #130
    Постоялец форума Аватар для Guffy
    Пол
    Мужской
    Адрес
    Одесса
    Возраст
    51
    Сообщений
    1,356
    Репутация
    256
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Тогда не надо пользоваться динамическими переменными и аргументами функций.
    А никто не обещал, что 3*lenght меньше 1мб
    фишка и была в том, что размер заранее неизвестен и как весело это выглядит с malloc/free

    Цитата Сообщение от homo ludens Посмотреть сообщение
    ладно, тут побороли

    Цитата Сообщение от homo ludens Посмотреть сообщение
    И сильно в мультитриде отладчик помогает?
    Нормально помогает, не беспокойтесь
    Все при бряке потоки тормозятся и над каждым можно провести показательные пытки (стек, локальные переменные в каждом фрейме)

    Цитата Сообщение от homo ludens Посмотреть сообщение
    Имхо техника программирования, когда кодер вместо того чтобы продумать кусок кода а потом написать - гоняет цикл do {написал-запустил-посмотрел watch-исправил} while (watch переменная несовпадает с ожидаемой) дает намного больше глюков, чем любой void*.
    А Вы, стало быть, написав 200-300 строк кода всегда попадаете в десятку? 1-2 глючка в некоторых случаях на такое кол-во строк, написанных сходу - это не преступление. У уж лучше "увидеть", чем "втыкать" (или натыкивать printf где надо и не надо).
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Плюс непотопляемую уверенность в правильности этого куска кода и что виноват в глюке кто-то другой...
    Уверенность и вышеописанный цикл - это ортогональные вещи. одно другому не мешает.

    Цитата Сообщение от homo ludens Посмотреть сообщение
    Однопоточные программы ушли, сейчас век недетерминированного кода...
    Раньше было все проще...
    Многопоточный становиться недетерменированным, если плвать в знаниях и не иметь опыта. Иначе - не так страшен черт...

  11. Вверх #131
    Частый гость Аватар для homo ludens
    Пол
    Мужской
    Сообщений
    751
    Репутация
    141
    Цитата Сообщение от Guffy Посмотреть сообщение
    А никто не обещал, что 3*lenght меньше 1мб
    фишка и была в том, что размер заранее неизвестен и как весело это выглядит с malloc/free
    переменные временные, наружу не экспортируются, так что все ок.
    А если используешь временные переменные больше 1Мб - ну, тут уже проблемы с логикой и дизайном, имхо. Переполнить стек можно не только через alloca.
    Цитата Сообщение от Guffy Посмотреть сообщение
    Нормально помогает, не беспокойтесь
    Все при бряке потоки тормозятся и над каждым можно провести показательные пытки (стек, локальные переменные в каждом фрейме)
    В мультитриде основной глюк - race condition. Вот он не ловится ничем.
    Я видел сервер, который два года работал без проблем на одной машине. А когда переставили на другую (с перекомпиляцией) - сдох.
    Временные проскальзывания между тридами поменялись и попали на критический участок. Вот и весь недетерминизм. И отладчик тут не поможет, только логгирование участков кода и запуск на стресс-тестах - пару недель минимум в цикле плюс случайные временные задержки в разных потоках. И то хрен помогает.
    Сам сколько раз видел - сидит чел и видит в дебаггере все ок. А без дебаггера - креш. И понять не может почему так.

    Цитата Сообщение от Guffy Посмотреть сообщение
    А Вы, стало быть, написав 200-300 строк кода всегда попадаете в десятку? 1-2 глючка в некоторых случаях на такое кол-во строк, написанных сходу - это не преступление. У уж лучше "увидеть", чем "втыкать" (или натыкивать printf где надо и не надо).
    Я всегда пишу сначала интерфейсы, а только потом имплементацию.
    А потом - тест-модуль.
    И вот потом, запуская код сравниваю выходы теста с ожидаемыми.
    Что я могу в дебаггере - посмотреть массив 1Мб? Я лучше его выведу в файл и сделаю diff с образцом - это лучше покажет ошибки.
    А если на моей машине работает, а на удаленной нет? Я запущу тот же make test, а вот с дебаггером там смотреть может быть проблематично.

    А если программка должна считать 2 недели на кластере из 4-х компов?
    Сидеть все это время перед экраном?
    Здесь вообще только логгирование помогает. А если сервер работает 24x7 и надо гонять стресс-тесты для определения MTBF? Откуда я знаю сколько раз он за неделю стресс-теста дал отказ в сервисе? Из дебаггера?

    Дебаггером пользуюсь в среднем два-три раза в год в следующих ситуациях.
    1. На машине заказчика креш. Тогда для анализа core dump можно взять gdb. Давно такого не было, так как практически все core dump отлавливаются valgind'ом на стресс-тестировании.
    2. На машине заказчика или у меня при тесте подвисание из-за дидлока. Вот это бывает. Тогда аттачу дебаггер и делаю снимок стека всех потоков (а их может быть сотня) в текстовый файл. И на нем сразу видны точки deadlock.

    Единственное, что у клиента должна быть версия откомпиленная с отладочной информацией. Клиенты обычно не протестуют - это условие поддержки.

    Цитата Сообщение от Guffy Посмотреть сообщение
    Уверенность и вышеописанный цикл - это ортогональные вещи. одно другому не мешает.
    Эх если бы так было... Стандартная отмазка - в дебаггере все работает.

    Цитата Сообщение от Guffy Посмотреть сообщение
    Многопоточный становиться недетерменированным, если плвать в знаниях и не иметь опыта. Иначе - не так страшен черт...
    Многопоточный код на языках без поддержки многопоточности всегда недетерминирован. Так как триды между собой не синхронизированы есть вероятности общего обращения к куску памяти или канселляции потока в неподходящий для него момент или рекурсивной блокировки и т.п. И на разных машинах и при разных условиях это будет всегда по разному.
    И ошибки такого типа отлавливаются очень тяжело. Забытый программистом мютекс может вылезти потом через год эксплуатации.
    А дебаггер покажет, что все в порядке.
    Последний раз редактировалось homo ludens; 11.05.2007 в 13:24.
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  12. Вверх #132
    Постоялец форума Аватар для Guffy
    Пол
    Мужской
    Адрес
    Одесса
    Возраст
    51
    Сообщений
    1,356
    Репутация
    256
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Многопоточный код на языках без поддержки многопоточности всегда недетерминирован. Так как триды между собой не синхронизированы есть вероятности общего обращения к куску памяти или канселляции потока в неподходящий для него момент или рекурсивной блокировки и т.п. И на разных машинах и при разных условиях это будет всегда по разному.
    И ошибки такого типа отлавливаются очень тяжело. Забытый программистом мютекс может вылезти потом через год эксплуатации.
    А дебаггер покажет, что все в порядке.
    Вот тут мы и расходимся.
    Несколько простых правил, и все будет пучком.
    Ну, например:
    1. Общие ресурсы всегда внутри мютекса (или критической секции, как у нас, "виндузятников"). Причем держать нужно не меньше, но и не больше чем нужно.
    2. Стараться избегать всеми возможными способами блокировать больше 1го ресурса за раз. Если уж надо 2 - сидеть, думать.
    3. Потоки стараться принудительно не прибивать, а взводить им соотв. евент - "тормози, братан, приехали" - и сам поток делает красивый ретурн из поточной функции
    Ну и как всегда - опытный мен на ЦПП в 99,9% случаев просто не теряет ни памяти, ни мютексов. Культура пользования автоматическими обертками к ресурсам просто практически не оставляет лазеек.
    зы: рекурсивные блокировки - критические секции позволяют повторный вход того же потока.

  13. Вверх #133
    Частый гость Аватар для homo ludens
    Пол
    Мужской
    Сообщений
    751
    Репутация
    141
    дык это все понятно и алфавитная сортировка блокировок и все остальное делается. И продумывать код надо.
    Проблема-то в другом, если ошибка программиста в сложном коде, то черта с два ее отловишь за разумный промежуток времени. И даже стресс-тесты не очень помогают.
    И средств автоматических отлова почти нет. Hellgrind есть, но у него много ложных срабатываний.

    А потом у клиента сто пудов всплывет - проверено.

    А насчет флага - это конечно хорошо, сам стараюсь так делать, но если только поток не занят в блокирующем вводе-выводе. Тут приходится канселляцию делать с очисткой ресурсов и прочей фигней. Крайне гемморойная вещь. И обвертки тут не очень помогают.
    У меня вот поток базу данных читает и асинхронно к ней никак не обратиться.

    Вообще на десятке потоков и на одном-двух компах недетерминированность не особо заметна, а вот как под сотню потоков переваливает и на разных компах, да на двухядерных...

    PS
    рекурсивные мютексы вроде непереносимы. На линухе я их юзаю в полный рост, а вот если под что другое надо будет портировать - хз что делать.
    А жаль, удобная штука. Хотя слышал, что очень затратны, по сравнению с обычными.
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  14. Вверх #134
    Постоялец форума Аватар для Guffy
    Пол
    Мужской
    Адрес
    Одесса
    Возраст
    51
    Сообщений
    1,356
    Репутация
    256
    Цитата Сообщение от homo ludens Посмотреть сообщение
    А насчет флага - это конечно хорошо, сам стараюсь так делать, но если только поток не занят в блокирующем вводе-выводе. Тут приходится канселляцию делать с очисткой ресурсов и прочей фигней. Крайне гемморойная вещь. И обвертки тут не очень помогают.
    У меня вот поток базу данных читает и асинхронно к ней никак не обратиться.
    И тут они (обертки, возможно несколько другого вида) очень даже помогают. Если заранее известно, что поток будет работать с таким ресурсом, что иногда прийдется тупо прибивать функцию потока и остаток ее не выполнится (и соотв. не вызовутся деструкторы локальных переменных), то для такого потока пишется специальный класс потока, в котором все ресурсы - поля класса. И функция потока не должна оперировать подобными ресурсами на стеке - только пользоваться полями класса. В итоге за освобождение отвечает дестуктор объекта поток.
    Либо ресурсы управляются обертками типа "смартпоинтер" и "хорошем" случае подчищаются функцией потока при выходе, в "плохом" - деструктором объекта поток (т.е. если например, деструктор потока видит, что в одном из полей мютекс, и функция потока при выходе его не разлочила - от его отпускает).
    И тут нам ЦПП помогает

  15. Вверх #135
    Не покидает форум Аватар для Ull9
    Пол
    Мужской
    Адрес
    Мюнхен
    Сообщений
    19,028
    Репутация
    1490
    я позволю себе реплику здесь.
    все эти обертки, с которыми наш оппонент согласился в С просто несуществуют, т.к там деструктора нет.

  16. Вверх #136
    Постоялец форума Аватар для Guffy
    Пол
    Мужской
    Адрес
    Одесса
    Возраст
    51
    Сообщений
    1,356
    Репутация
    256
    вот этими простыми "бытовыми" удобствами я его и добиваю

  17. Вверх #137
    Частый гость Аватар для homo ludens
    Пол
    Мужской
    Сообщений
    751
    Репутация
    141
    здесь есть ряд спорных моментов, хотя возможно я что-то не понимаю в С++ реализациях этого дела.

    Во первых при канселляции потока через pthread_cancel в точке канселляции в режиме DEFERRED (напрмер ожидании синхронного файлового ввода типа read socket) деструкторы автоматических переменных вызываться не могут - канселляция тупо очищает стек и убивает трид. Возможно что в С++ есть высокоуровневые методы обхода этого, однако мне они неизвестны.
    В С я об этом не беспокоюсь, так как деструкторов нет, а очистка стека - нормальная процедура при выходе из функции. В С++ у меня гарантированно останется мусор в памяти, либо я должен отказаться от локальных смарт-пойнтеров и т.п. Все те мелкие радости которые дает обвертка динамической памяти в автоматическую переменную здесь становятся крупными пакостями и то, что будет хорошо работать в try-cath блоке сдохнет в таких функциях.

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

    Единственная реальная проблема здесь - динамическая память, удаление которой делается через pthread_cleanup. Способ не самый удобный, хотя по сути представляет собой тот же деструктор.
    Неудобство заключается в том, что точек канселляции может быть (и обычно бывает) несколько и на каждую из них надо писать свой cleanup handler, так как ресурсы могут быть распределены в этих точках по разному, а контролер ресурсов сильно утяжеляет трид.

    Кстати, alloca я использую в основном в функциях, где возможна канселляция - позволяет уменьшить код cleanup handler, а то и вообще его избежать.

    Во вторых обвертка для потока - тоже вещь не самая прозрачная. Очевидно, что в случае канселляции деструктор обвертки не может выполнятся в стеке собственного потока - т.е. возникает менеджер потоков. Если же трид хочет убить себя корректно, то команду этому менеджеру он должен отослать асинхронно - возникает очередь сообщений между всеми потоками и менеджером. либо должно быть два варианта деструктора - для вызова в стеке потока (например через pthread_join) и для внешнего с канселляцией. Т.е. геморрой есть в любом случае и имхо языковые конструкции тут мало что дадут.

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

    Впрочем про высокоуровневые средства С++ для мультипотока мне ничего неизвестно, я работаю с POSIX интерфейсом и там все так как я описал. Возможно что я что-то не знаю в современном С++.
    С другой стороны средства работы с потоками предоставляет ОС и они от языка вроде мало зависят.
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  18. Вверх #138
    Не покидает форум Аватар для Ull9
    Пол
    Мужской
    Адрес
    Мюнхен
    Сообщений
    19,028
    Репутация
    1490
    pthread_cancel, насколько я понимаю довоьно грубая и сильная вещь. конечно из пушки по воробьям можно и столбы повалить. можно например abort(), вызвать,а потом сетовать, что деструкторы не сработали.

    я не пользуюсь ПОСИКСо, как по мне это сильно муторно с этим АПИ работать.
    из-за слишком низкоуровневого АПИ, сложно разглядеть логику. И не надо меня убеждать, что больше контроля. Сколько нужно контроля столько я и беру.
    что можно отдать компилятору, деструкторам, врапперам, отдаю им. они не ошибаэтся, в отличие от меня.
    как, ты верно подметил существуют очень хорошие обeртки вокруг этого дела.
    Они учитывают и посикс и платформозависимые вещи тоже, так что код получается квазипортабельным.
    Я пользуюсь АСЕ, классая вещь, все есть и треды и атомик переменные и сокеты, болле сложны, например проактор. И все обьектами. и нет никаких проблем о которых ты писал.
    Последний раз редактировалось Ull9; 12.05.2007 в 15:09.

  19. Вверх #139
    Не покидает форум Аватар для Ull9
    Пол
    Мужской
    Адрес
    Мюнхен
    Сообщений
    19,028
    Репутация
    1490
    Цитата Сообщение от homo ludens Посмотреть сообщение
    блин, пока сидел в работе набежало много постов...

    по порядку.
    pimpl - неважно, приватные члены или нет - при любом их изменении возникает перекомпиляция, так как они занимают место. Перекомпиляция возникает и при смене методов класса, но - методы класса всегда более стабильны чем члены.
    Выход - переместить их в приватный класс и реализовать pimpl без членовы класса, любых - приватных или публичных, заменив акцессорами.
    Если же pimpl-класс без членов, то он решает те же задачи, что и интерфейс, а тогда нафиг он нужен? Интерфейс намного гибче и расширяемей.
    при любом подходе, измение кода влечет перекомпиляцию. ЛЮБОМ, иначе как код будет изменен? Вопрос только в том что пимпл и интерфейсы позволяют УМЕНьШИТь обем перекомпиляции. далее. интерфейс не всегда возможен. Например прямо сейчас у меня контракт, в котором сказано maintenance, понятно? не могу я код перелопачивать! НЕМОГУ. максимум, что могу делать forward declaration or pimpl.
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Я знаю, что языки без сохранности типов позволяют намного более скоростную разработку программ, но на больших объемах кода дают дополнительный рост глюков.
    О, что и следовало доказать. На больших программах рост глюков. А маленьких, я к слову сказать уже лет 10 не видел
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Как воид* провоцирует подход по двойному объявлению типов - мне непонятно. Имхо программисту - программистово а архитектору - архитекторово. И код написанный программером должен обязательно читаться кем-то другим, хотя бы его напарником (если речь идет об XP).
    Увы, в реальной практике, почти всегда нехватает людей, которые будут проерять твой код. Только тестер. и то, он же не код проверяет.

  20. Вверх #140
    Частый гость Аватар для homo ludens
    Пол
    Мужской
    Сообщений
    751
    Репутация
    141
    Цитата Сообщение от Ull9 Посмотреть сообщение
    pthread_cancel, насколько я понимаю довоьно грубая и сильная вещь. конечно из пушки по воробьям можно и столбы повалить. можно например abort(), вызвать,а потом сетовать, что деструкторы не сработали.
    pthread_cancel может быть вполне безопасен, просто не надо объявлять трид с асинхронным канселлированием (это действительно похоже на abort), а с режимом DEFERRED. Это означает, что канселляция возможна только в точке проверки через pthread_testcancel или в процедуре синхронного файлового ввода/ввода. Т.е. техники вполне безопасны если их правильно применять. Однако как ты правильно заметил - муторны.
    Правда, как я понимаю это единственный способ остановить поток в ожидании с очисткой ресурсов. Или надо вешать контроллер ресурсов, вещь в принципе возможную, но очень тяжелую, т.е. каждое распределение/удаление памяти надо заносить в список ресурсов и потом при убийстве потока их чистить. В реалтаймовых системах это может быть накладно. Опять таки в самом контроллере ресурсов надо блокировать канселляцию для обеспечения атомарности - в общем система та еще получается.

    С другой стороны мне непонятно вот что. Есть обвертка чужого кода, которая юзает POSIX, и я хочу этой обверткой убить трид. Причем этот трид в этот момент висит допустим в синхронном чтении и чтение это не обернуто, а просто мне в триде захотелось допустим сделать getline из файлового дескриптора или sleep или еще что-то затратное по времени и неизвестно когда завершающееся.
    Каким образом обертка узнает какие ресурсы я в этот момент распределил и какие надо убить?
    Вот пример
    Код:
    void func(void)
    {
      foo f;
      bar *b=new bar;
    
      sleep(100000);
      delete b;
    }
    Убить такой поток не дожидаясь конца слипа можно только канселом. Если есть доплнителные возможности операционки, тогда может существует другое решение, но под линуксом например стадартная библиотека - POSIX. Подозреваю что под AIX - тоже.

    Но в этом случае не выполнятся деструкторы f и b, хотя память под f будет очищена.
    Для b можно придумать способ через контроллер ресурсов обвертки. Т.е. конструировать объект через factory связанный с обверткой потока либо просто анализировать в конструкторе базового типа bar pthread_self и заносить в таблицу распределенных ресурсов.
    А вот что делать с foo? Я не знаю метода, который бы позволил корректно выполнить деструктор в такой ситуации, причем это никак не зависит от наличия или отсутствия обвертки (если она использует POSIX, а это все-таки стандарт). Даже если оборачивать все sleep/read/recv/getline и т.п. другими функциями и пользоваться только высокоуровневыми вызовами.

    Цитата Сообщение от Ull9 Посмотреть сообщение
    Я пользуюсь АСЕ, классая вещь, все есть и треды и атомик переменные и сокеты, болле сложны, например проактор. И все обьектами. и нет никаких проблем о которых ты писал.
    Про ACE слышал очень много хорошего, однако сам с ним не успел поработать. С другой стороны в годы увлечения CORBA пытался запустить TAO (их смежный продукт) - увы, мне не удалось его даже скомпилировать. Сейчас наверное ситуация изменилась к лучшему, но тогда (2002 +-год) это был продукт выглядевший очень сыровато.
    The future is already here - it is just unevenly distributed. (c) W. Gibson


Ответить в теме
Страница 7 из 8 ПерваяПервая ... 5 6 7 8 ПоследняяПоследняя

Социальные закладки

Социальные закладки

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения