avva: (Default)
[personal profile] avva

Наткнулся на старую статью Александреску о том, как можно использовать ключевое слово volatile с объектами (а не примитивными значениями, как обычно) в C++, для того, чтобы лучше многопоточные программы писать.

Интересная техника! Но любопытно то, что Александреску нигде не отмечает, насколько предлагаемое им использование слова volatile не зависит, на самом деле, от его "смысла". Пусть меня поправят, если я неправ, но мне кажется, что предлагаемое автором использование volatile только при определении объектов, а также полей и методов классов, которые могут без опаски быть использованы одновременно разными потоками - тут volatile вообще ничего не делает с точки зрения компилируемого кода (volatile может что-то делать при использовании с примитивными типами, но как раз этого Александреску советует не делать, а заворачивать их в таких случаях в объекты!).

Иными словами, то, что нужно, это некое абстрактное ключевое слово foobaric, так чтобы: а) любой объект можно было объявить foobaric; б) в таком случае его члены автоматически становятся foobaric; в) метод класса можно было объявить foobaric; г) foobaric-объект может вызывать только foobaric-методы своего класса; д) от объекта можно отобрать его foobaric-сущность каким-нибудь приведением.

Если у нас есть такой foobaric, то мы можем сделать умный указатель а-ля Александреску, который все время своей жизни проводит внутри мьютекса, и переводит вызовы foobaric-объекта, которым был инициализирован, в вызовы того же объекта без foobaric, который он сохранил внутри путем приведения.

Александреску делает это при помощи foobaric==volatile, но это не использует ничего из "настоящей" семантики volatile, а просто применяет volatile в качестве такого foobaric-маркера. Можно было бы, например, в качестве foobaric использовать const и mutable (для методов), но тогда "настоящая" семантика const мешалась бы под ногами. Сам факт того, что для решения этой проблемы пришлось "позаимствовать" вообще-то предназначенное для другого (хоть на первый взгляд и родственного) слово volatile, указывает на то, что, возможно, стоит иметь гибкую поддержку такого рода "маркеров" прямо в языке. И тут, видимо, мне самое время прочитать статьи про Traits, которые недавно бросил в закладки, но пока не добрался...

Date: 2007-01-22 01:53 am (UTC)
From: [identity profile] msh.livejournal.com
Метод интересный, но практически неприменимый. По двум причинам

1. В большинстве более-менее серьезных real-time приложениях не два класса операций, а больше. Например, ну что бы такого широко известного .. ну, скажем, linux kernel. Есть классы 1) может спать 2) может сидеть в спинлоке 3) медленная операция (нельзя использовать в interrupt handler) и т.п.

2. Механическое принудительное использование операций с локами для доступа к shared objects (a-la java) неэффективно. Программисту даден мозг на то, чтобы смотреть есть race condition или нет

Date: 2007-01-22 06:33 am (UTC)
From: [identity profile] pargentum.livejournal.com
1. Ну так последний абзац - про Traits - ровно про это. Что во многих приложениях одним словом volatile не обойтись и хотелось бы много таких слов.

2. У программиста мозг стоит денег за каждый отработанный час. А компилятор работает практически забесплатно. Поэтому переложить хотя бы часть работы с программиста на компилятор - дело хорошее и правильное (хотя и не всегда получается, да).

Другое дело, что на одних traits избавиться от race condition все равно не получится...

Какой текст!

Date: 2007-01-22 01:57 am (UTC)
dkuzmin: (Default)
From: [personal profile] dkuzmin
Прямо вот так бы сразу в антологию.

Re: Какой текст!

Date: 2007-01-22 09:49 am (UTC)
From: [identity profile] avva.livejournal.com
Ну-ну :)

Date: 2007-01-22 03:17 am (UTC)
From: (Anonymous)
Да, Вы совершенно правы. James Kanze назвал это "an abuse of the type system". А техника остроумная, но совершенно бесполезная. И формально неверная: то, что делает Александреску, - в C++ undefined behavior.

Date: 2007-01-22 09:49 am (UTC)
From: [identity profile] avva.livejournal.com
Согласен насчет abuse. Но не очень понятно, почему формально неверная и undefined behavior - можете пояснить?

Date: 2007-01-22 10:45 am (UTC)
From: (Anonymous)
В сущности, Александреску предлагает к volatile-объекту (то, что объект должен быть объявлен как volatile, - необходимое условие для использования этой техники) обращаться как к non-volatile-объекту (что разумно: в критической секции volatile вреден). Но как раз это в C++ формально недопустимо: "If an attempt is made to refer to an object defined with a volatile-qualified type through the use of an lvalue with a non-volatile-qualified type, the program behaviour is undefined." (7.1.5.1/7 в стандарте).

Date: 2007-01-22 11:13 am (UTC)
From: [identity profile] avva.livejournal.com
Да, понятно. Спасибо!

Date: 2007-01-22 04:16 am (UTC)
From: [identity profile] gaius-julius.livejournal.com
о господи, только не ещё одна "гибкая поддержка" чего-нибудь в C++. на нем сейчас-то никто не хочет начинать писать из-за чрезмерной сложности...

Date: 2007-01-22 07:52 am (UTC)
From: [identity profile] alex-vinokur.livejournal.com
Боятся не "чрезмерной" сложности C++, а его "чрезмерных" возможностей. Когда пишешь на C, все, вроде бы, под контролем. Хотя это не так.
P.S. Лет 5-7 тому назад попытки использовать C++ в Embedded systems встречали жестокое сопротивление. Сейчас C++ используют в Embedded systems, но такое же жестокое сопротивление встречают попытки использования STL.

Date: 2007-01-22 08:00 am (UTC)
From: [identity profile] gaius-julius.livejournal.com
да, наверное точнее будет "возможностей" (...приводящей к чрезмерной сложности. Челоек, писавший на С++ 5 лет назад, сейчас не сможет легко разобраться в современном коде), что-то такое я имел ввиду. Правда, сравнивать с C ни в коем случае не собирался.

P.S. Это несколько из другой оперы, как мне кажется

Date: 2007-01-22 09:49 am (UTC)
From: [identity profile] avva.livejournal.com
Не, я не предлагаю конкретно в C++, я так, вообще.

Date: 2007-01-22 04:21 am (UTC)
From: [identity profile] ivan-gandhi.livejournal.com
А нельзя просто на джаве программировать?

Date: 2007-01-22 04:37 am (UTC)
From: [identity profile] gaius-julius.livejournal.com
просто программировать ни на чём нельзя (-:

Date: 2007-01-22 08:13 am (UTC)
From: [identity profile] migmit.livejournal.com
Нельзя.
(deleted comment)

Date: 2007-01-22 07:46 pm (UTC)
From: (Anonymous)
В Java, даже до версии 5 (она же 1.5), было не "точно так же", поскольку имелась формальная модель памяти для многих потоков управления. Начиная с Java 5, модификатор volatile перестал быть бесполезным, хотя чтобы его корректно использовать, надо очень хорошо понимать 17-ю главу JLS.

Евгений Д.

Date: 2007-01-22 09:50 am (UTC)
From: [identity profile] avva.livejournal.com
А людей не жалко? :)

Date: 2007-01-22 09:13 am (UTC)
From: [identity profile] iratus.livejournal.com
Прочитав статью, в очередной раз для себя убедился,
что ООП в форме С++- это ужас...
А уж серьезный мультитрединг в С++ - это ужас в квадрате
:))


Date: 2007-01-22 09:50 am (UTC)
From: [identity profile] avva.livejournal.com
С этим не поспоришь.

Date: 2007-01-22 10:03 am (UTC)
From: [identity profile] iratus.livejournal.com
Не ну например на Java/C# писать мультитрединг вполне удобно (хотя я на Java все равно пишу как на С :)) )
Но С++... кстати Objective C судя по всему тоже очень удобен.. надо бы к нему серьезней отнестись....

А вообще мне кажется что серьезный мультитрединг надо писать на POSIX threads без всяких там абстракций, энкапсуляций и т.п. Потому что на гоночную машину не ставят автоматическую коробку передач.

Date: 2007-01-22 06:49 pm (UTC)
From: [identity profile] siludin.livejournal.com

А вообще мне кажется что серьезный мультитрединг надо писать на POSIX threads без всяких там абстракций, энкапсуляций и т.п. Потому что на гоночную машину не ставят автоматическую коробку передач.


Популярное заблуждение. Ручная передача может стоять на дорожном спортивном автомобиле, водитель которой хочет почувствовать себя крутым гонщиком. А на Формулах-1 ставят автоматические коробки, которые гораздо эффективнее самого лучшего гонщика с ручной коробкой. Единственная причина, по которой в некоторых гоночных машинах не используют автомат - это то, что это запрещено правилами, как unfair advantage.

Похоже, то же самое и с программированием. Cool 3133T hackers могут писать на ассемблере. Однако компании, которые рулят, не чураются прогресса.

Но вот в чем я соглашусь. Хорошему программисту нужно знать, что происходит под уровнем абстракции, с которым он работает, хотя бы на 1 уровень вниз. То есть настоящий шумахер обязан уметь водить как на ручной коробке, так и на автомате :)

Date: 2007-01-27 12:49 pm (UTC)
From: [identity profile] shigin.livejournal.com
Во первых в формуле--1 разрешали пользоваться полностью автоматическими коробками. Но гонщики все равно переключали передачи в ручную (Михаэль говорил, что перед поворотом я переключаю передачу на одну вверх, что бы лучше контролировать прохождение). Во вторых в Ф1 и на дорожных машинах стоят разные по принципу коробки передач.

Вот если бы вы сказали про антипробуксовочную систему или launch control, то с вами осталось бы только молча согласится.

Date: 2007-01-26 04:11 am (UTC)
From: [identity profile] malaya-zemlya.livejournal.com
:кстати Objective C судя по всему тоже очень удобен.

Опыт у меня с ним самый негативный.
Один reference-counted gargage collection сколько нервов испортит. А про эппловский IDE (который Xcode) уже и не говорю.

Date: 2007-01-22 09:54 am (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
а на чем порекомендуете серьезный мультитрединг?

Date: 2007-01-22 09:59 am (UTC)
From: [identity profile] avva.livejournal.com
Erlang вот хвалят.

Date: 2007-01-22 11:21 am (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
Это да. Правда, языки с передачей сообщений, кажется, сильно оставляют позади и Java/c#/pthreads, не говоря уже об С++, вообще ни с какой парадигмой мультитред-программирования не "пожененный".

Но пинают почему-то как раз С++.

И спасибо за рекомендацию.

Date: 2007-01-22 05:13 pm (UTC)
netch: (Default)
From: [personal profile] netch
Ой не надо. 1) такой же message passing реализуется на тех же C/C++ небольшой библиотекой, и это тоже полезный иногда вариант дизайна. 2) производительность невысокая. В общем, если есть его за что ценить, так это за систему апгрейда на ходу. Всё остальное не более чем среднее.

Date: 2007-01-22 10:09 am (UTC)
From: [identity profile] iratus.livejournal.com
Ну если не выбирать экзотические (пока) варианты типа Эрланга, то на POSIX Threads модели. Она себя уже много раз доказала

Date: 2007-01-22 10:30 am (UTC)
From: (Anonymous)
простите, но разве язык С++ и pthreads - это не ортогональные вещи?

В чем смысл утверждения о том, что мультитрединг под pthreads лучше чем мультитрединг под С++?

Кто мешает использовать pthreads под С++? Или же С++ навязывает иные способы программирования мультитреда?

Date: 2007-01-22 10:31 am (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
это был я

Date: 2007-01-22 10:44 am (UTC)
From: [identity profile] iratus.livejournal.com
ответ ниже :)

Date: 2007-01-22 10:44 am (UTC)
From: [identity profile] iratus.livejournal.com
я нигде не утвержда что мультитрединг под pthreads лучше чем мультитрединг под С++. Проблема с С++ - это сложность в понимании/написании/употреблении мультитрединговой модели с точки зрения организации правильного доступа к данным/синхронизации и т.п.
сам факт необходимости написания такой статьи на которую ссылается Авва это доказывает.

В отличии от скажем Java/C# где написание нультитрединговой аппликации а также читабельность подобного кода ( в попытке понять что он делает и как работают намного облегчены).

А POSIX Threads/ C code - просто наиболее удобное сочетание для написания сложных мульитрединговых програм с элементами real-time

Date: 2007-01-22 11:15 am (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
По поводу Java/c# согласен. Собственно, это главное.

По мелочам:

> Проблема с С++ - это сложность в понимании/написании/употреблении мультитрединговой модели с точки зрения организации правильного доступа к данным/синхронизации и т.п.

Чего я не могу понять - это почему POSIX Threads/C code не страдает теми же проблемами, а наоборот есть "наиболее удобное сочетание для написания сложных мульитрединговых програм с элементами real-time".

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

В posix-threads на С без "плюсов" проблемы те же самые, просто там даже не будет шанса их решить, как попытался на С++ Александруску. Но от этого необходимость никуда не денется.

Date: 2007-01-22 02:08 pm (UTC)
From: [identity profile] palm-mute.livejournal.com
> В posix-threads на С без "плюсов" проблемы те же самые, просто там даже не
> будет шанса их решить, как попытался на С++ Александруску. Но от этого
> необходимость никуда не денется.

Плюсы добавляют проблем, т.к. больше шансов получить race condition в неожиданном месте из-за такой штуки, как время жизни объекта. Вот, например, древний thread (http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/e9447e4f8df38f68/158bb2b629d70dfb) на c.l.c++.m с говорящим названием "Destruction, Derivation, Synchronization, & Chaos", начатый бустоводом Gerhard Menzl.

Что характерно, boost::signals - библиотека похожего назначения с описанной в треде по ссылке - не поддерживает многопоточность (во всяком случае, не поддерживала, когда я на нее последний раз смотрел).

Другой пример - невозможность безопасно и переносимо реализовать синглтон Майерса, т.к. после вызова конструктора статического объекта нужно взвести некоторый скрытый флажок, и, значит, доступ к этому флажку нужно тоже синхронизировать, а возможности такой нет.

Можно еще взглянуть, насколько усложнена реализация boost::shared_ptr для корректной работы в многопоточной среде.

Т.е., резюмируя, попытки использовать так называемый "modern c++ design" в условиях многопоточности значительно повышают шансы нарваться на грабли.

Так что я присоединяю свое ИМХО к сообщениям ораторов, высказавшихся против наворотов в духе Александреску в многопоточных программах.

Date: 2007-01-22 03:52 pm (UTC)
From: [identity profile] avva.livejournal.com
Спасибо за ссылку на дискуссию, очень познавательно.

Date: 2007-01-22 04:27 pm (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
Я, в принципе, отвечал на утверждение о том, что то, что раз Александреску написал классы для автоматического локирования, то это свидетельствует о каких-то специфических проблемах С++, которых нет в С.

Но за "навороты в духе Александреску в многопоточных программах" я никак не агитирую. У меня та статья с обещаниями дать средство устранения race conditions в своё время вызвала лишь недоумённую улыбку.


Примеры Ваши действительно интересные.

Что до времени жизни объекта, то обычный С программист ведь тоже может "догадаться" начать уничтожать структуру данных, которая где-то еще зарегистрирована. Автор примера хотел получить некоторый автоматизм деригистрации из деструктора базового класса, который (автоматизм) кривыми средствами С++ красиво написать вроде бы не получается. Но в обычном С дерегистрацию тоже придется как-то вызывать, чтобы не получить того же самого race condition, и кто сказал, что это будет удобнее, чем делать это на С++? Ну да, хорошо бы всю дерегистрацию запрятать в деструктор базового класса, но можно ведь и не прятать, как и в С (без плюсов) никаких деструкторов не имеющем.

С++, конечно, не оправдывает некоторых естественных ожиданий, но желание дерегистрировать частично разрушенный класс - оно вовсе не естественно.

Date: 2007-01-27 07:16 am (UTC)
yigal_s: (Default)
From: [personal profile] yigal_s
> Можно еще взглянуть, насколько усложнена реализация boost::shared_ptr для корректной работы в многопоточной среде.

В этой реализации не увидел ничего для мультитреда, что было бы специфично связано с С++, но отсутствовало бы при попытке сделать что-то подобное на С. Этого нет ни в заложенных возможностях shared/weak_ptr, ни в его имплементации.

Иными словами, я понимаю, что код непростой, не вижу только как он станет проще под чистым С, а также не вижу, почему кто-то захочет отказаться от каких-то возможностей shared_ptr под С, желая их всё же иметь под С++.

Date: 2007-01-23 01:12 am (UTC)
From: [identity profile] 109.livejournal.com
написание нультитрединговой аппликации

нультитрединговая аппликация ака беспоточное приложение :-)

Date: 2007-01-22 02:37 pm (UTC)
From: [identity profile] dvv.livejournal.com
Александреску давно получил по сусалам за такие выкрутасы и где–то даже recanted. Это можно было живьём в Юзнете наблюдать нек. время назад. Параллельно с разборками по поводу double-checked locking.

Date: 2007-01-22 03:43 pm (UTC)
From: [identity profile] -pk-sly.livejournal.com
а всё потому что в С++ нет стандартного (а зачастую, даже и нестандартного) средства сделать что-то типа syncpoint или flush для всех (или конкретных) переменных, временно сохранённых в регистрах.

Date: 2007-01-22 06:52 pm (UTC)
From: [identity profile] siludin.livejournal.com
К слову, Александреску принимает очень живое участие в развитии языка D.

Date: 2007-01-22 07:46 pm (UTC)
From: [identity profile] avva.livejournal.com
Спасибо, не знал, интересно. Я собираюсь посмотреть на D когда-нибудь не в слишком отдаленном будущем.

Date: 2007-01-22 07:41 pm (UTC)
From: (Anonymous)
Использовать слово volatile действительно не comme il faut, за что Александреску и был раскритикован. Особенно досталось за предложение использовать volatile для синхронизации.

(A while ago, after having published "volatile: Multithreaded Programmer's best friend", the MT programmer community ripped my right leg and beat me to death with it. That was because my article had an introduction of the 'volatile' keyword that contained a number of gross inaccuracies, the main one being that volatile helps MT programming. For the record, the meat of the article still stands, but it's a shame it was blurred by some bads in the introduction., http://groups.google.com/group/comp.std.c++/msg/9ab9f0357570edb8)

Впрочем, volatile можно было бы заменить каким-то модификатором вроде safe_for_multithreaded_access. Однако непохоже, чтобы это решало хоть какие-нибудь значимые проблемы при написании многопоточного кода.

Насколько я понял идею, она состоит в том, чтобы с помощью системы типов обязать клиентский код "оборачивать" доступ к защищённым методам (к тем, у которых модификатор safe_for... отсутствует) мьютексом. Поскольку проконтролировать, какой именно мьютекс используется, так нельзя, этот метод даёт даже меньше чем просто разумная инкапсуляция доступа. Иными словами, если "незащищённый" метод доступен снаружи, необходимость захватить хоть какой-то мьютекс -- очень слабое условие.

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

Ещё одно замечание по поводу traits. Не факт, что свойства класса или объекта способны описать корректность многопоточного кода. Во всяком случае, довольно бесполезно маркировать thread-safety (бессмысленное словосочетание!) объектов нижнего уровня.

Более интересный, как мне кажется, подход -- возможность делать любые комбинации изменений атомарно, сохраняя тем самым сколь угодно сложные инварианты. См., например, Harris, Marlow, Peyton Jones, Herlihy, Composable Memory Transactions (http://research.microsoft.com/Users/simonpj/papers/stm/stm.pdf).

Евгений Д.

Date: 2007-01-22 08:05 pm (UTC)
From: [identity profile] avva.livejournal.com
Евгений, большое спасибо за ваши замечания и за ссылки на дискуссию и на статью. Статья очень интересная, буду читать. Приятно, когда журнальная запись вызывает такие квалифицированные ответы.

Date: 2007-01-22 08:39 pm (UTC)
From: (Anonymous)
И Вам спасибо за интересный журнал.

Евгений Д.

Date: 2007-01-23 01:54 am (UTC)
From: [identity profile] 109.livejournal.com
тема интересная, но я, видимо, не всасываю какой-то ключевой момент.

вот, предположим, придумали мы ключевое слово ThreadSafe, и радостно припендюрили его к нашим мультитредно-защищённым классам. а один класс (или метод) забыли. как мы найдём, что вот к этому классу вдруг в рантайме стали лезть из нескольких тредов одновременно? проблема-то ведь не в том, как замаркировать код как thread safe, а как предотвратить/идентифицировать мультитредный доступ к коду, который не thread safe.

Date: 2007-01-23 02:17 am (UTC)
From: [identity profile] avva.livejournal.com
Это-то как раз понятно вроде. Идея ключевого слова ThreadSafe состоит в том, чтобы компилятор заставлял нас выполнять определенный ритуальный танец всякий раз, когда мы пытаемся перейти от чего-то thread-safe к чему-то не thread-safe. Если мы какой-то класс забудем пометить как thread-safe, но в исходниках будем им пользоваться без ритуального танца, оно не скомпилируется.

Опасность именно обратная: что мы какой-то класс неправильно пометили как ThreadSafe. Тогда упс.

Date: 2007-01-23 09:28 am (UTC)
From: [identity profile] 109.livejournal.com
но в исходниках будем им пользоваться без ритуального танца, оно не скомпилируется.

вот это, как это будет достигаться, что не скомпилируется?

вот есть что-то не thread safe, с чем мы работаем однотредно. никаких "ритуальных танцев" пока мы требовать не можем, ибо должны подчиняться принципу "платим только за то, чем пользуемся". и вдруг в какой-то момент мы бах! и доступаемся к этому из другого треда. в рантайме это, предположим, отловить можно, а при компиляции-то как?

Date: 2007-01-23 09:46 am (UTC)
From: [identity profile] avva.livejournal.com
вот это, как это будет достигаться, что не скомпилируется?

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

вот есть что-то не thread safe, с чем мы работаем однотредно. никаких "ритуальных танцев" пока мы требовать не можем, ибо должны подчиняться принципу "платим только за то, чем пользуемся". и вдруг в какой-то момент мы бах! и доступаемся к этому из другого треда. в рантайме это, предположим, отловить можно, а при компиляции-то как?

От нас тут требуется, чтобы мы и при однотредной работе в исходнике выполняли виртуальный танец, когда имеем дело с non-thread-safe объектом. Конечно, это нарушает принцип "платим только за то, чем пользуемся", и в конечном итоге для того, чтобы соблюдать этот принцип, нам приходится заранее решать, какой код никогда никогда не будет мультипоточным, и просто не пользоваться для ним этим методом; а если все же окажется, что его вызовут, то баг и капут.

January 2026

S M T W T F S
    1 2 3
4 5 6 7 8 910
11 12 1314151617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 15th, 2026 02:37 pm
Powered by Dreamwidth Studios