Многопотоковые приложения под Windows
Например, есть некоторая функция, выполняющаяся в основном потоке. В ней имеется локальная переменная-структура, затем создавались один или несколько дополнительных потоков, в которые передавался указатель на эту локальную структуру. Затем в этойже функции ожидалось завершение работы потоков. Вот здесь-то я и столкнулся с первой неприятностью. Переменная локальная, значит может учавствовать в оптимизациях,и поэтому переданный указатель будет уже не действителен. Пробему решил либо ключевым словом volatile, либо описанием не локальной, а глобальной структуры.
Еще один глюк схватил,когда передал в поток указатель на класс, и в нем вызывал методы класса по этому указателю. Исправил обращением непосредственно к переменной класса непосредственно, через extern (класс и поток были в разных модулях). Так и не понял причину глюка. Одним словом, подводных камней тьма! Если кто-то имел хороший опыт в подобной теме,прошу поделиться опытом, может литературу какую грамотную посоветуете, как это все "крутиться" на низком уровне, а то алгоритмически вроде все верно, ан нет...
Работать с полями объекта через блокирующие вызовы, используя семафоры, мьютексы, события (events). Естественно, инкапсулируя синхронизацию внутри класса. Ещё нужно следить за тем, чтобы не случались dead-lock"и (смертельных объятий) - циклическое ожидание двух и более потоков.
Идет обработка одного блока данных, нужно распараллелить этот процесс, как это сделать более корректно? Как здесь без указателя?
Ну так это я уже давно понял, это не то что не хороший,я бы даже отнес к неправильным действиям. Как раз структура по этому указателю "исчезала" время от времени
а кто сказал от них отказываться??? просто память надо под объекты в куче выделять. т.е. через оператор new. а потом, есессно, явно их удалять. тогда объекты не будут "самопроизвольно" умирать
Переменная локальная, значит может учавствовать в оптимизациях,и поэтому переданный указатель будет уже не действителен.
В каких оптимизациях? Почему будет невалиден?
Все будет валидно в пределах срока жизни переменной.
Проблемы лишь с синхронизацией записи значений в эту переменную (впрочем, как и влюбую другую).
Еще один глюк схватил,когда передал в поток указатель на класс, и в нем вызывал методы класса по этому указателю. Исправил обращением непосредственно к переменной класса непосредственно, через extern (класс и поток были в разных модулях). Так и не понял причину глюка.
Опять же, проблема не в указателе, а в разных модулях и синхронизации записи.
Одним словом, подводных камней тьма!
Да нет особых проблем. Просто, обеспечь синхронизацию доступа.
Фраза не понятна. Разве объекты - это не экземпляры структур?
Работать с полями объекта через блокирующие вызовы, используя семафоры, мьютексы, события (events).
Только если поле может быть изменено, причем не атомарно.
Естественно, инкапсулируя синхронизацию внутри класса.
Откуда такая категоричность? Почему бы не использовать внешнюю (про отношению к объекту) синхронизацию?
Не хороший стиль использовать ссылки(указатели) на локальный объект. Никто не гарантирует тебе, что ссылка(указатель) является валидным.
Это не так. Гарантией является ожидание завершения порожденного потока, о чем и говорил автор топика: "Затем в этойже функции ожидалось завершение работы потоков."
Извиняйте, привык к C# :o
Конечно имелся в виду доступ на запись. :rolleyes:
По-моему, на начальных этапах написания кода так проще мыслить.
Все будет валидно в пределах срока жизни переменной.
Проблемы лишь с синхронизацией записи значений в эту переменную (впрочем, как и влюбую другую).
Опять же, проблема не в указателе, а в разных модулях и синхронизации записи.
Да нет особых проблем. Просто, обеспечь синхронизацию доступа.
А зачем тогда volatile, для красоты? и почему бы компилятору не кинуть переменную в регистр процессора?
----
Так в том то и дело,что все эти глюки проявлялись даже если дополнительный поток один, а главный ожидает его завершения, здесь ничего синхронизировать даже не нужно. К тому же если работают несколько потоков, то они пишут в непересекающиеся адреса блока, место под который выделялось оператором new в главном потоке и указатель на него передавался в вспомогательные. Может глюк заключался в другом, сейчас приведу описание:
1. Есть ГЛОБАЛЬНАЯ переменная класса (C)
2. В этом классе выделяется место под блок
3. В одном из методов создается новый поток, которому в передается указатель на этот класс, и происходит ожидание завершения работы.
4. В основной функции потока происходит вызов другого метода тогоже класса по переданному указателю, в котором и осуществлялась запись в блок.
При такой схеме, иногда оказывалось, что в блок ничего не писалось или писалась какая-то белеберда. Исправилось это все, если только в функции потока не использовать переданный указатель, а непосредственно обращаться к переменной класса.
И насчет локальной переменной: часть параметров передавалось через указатель на локальную структуру в функции, где создавался доп. поток, при этом опять же таки значения по этому указателю в потоке оказывались далеки от истенных (опять же не всегда). Исправилось объявлением этой структуры как глобальной. Может это конечно все совпадения, но тем не менее, факт есть факт.
Обратись к документации, что бы узнать зачем:
[QUOTE=MSDN]
The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something such as the operating system, the hardware, or a concurrently executing thread.
[/QUOTE]
Перевожу: для того, чтобы указать, что переменная может быть изменена извне (относительно потока).
Остальная информация в MSDN отвечает на вопросы "как" и "почему", а не "зачем".
и почему бы компилятору не кинуть переменную в регистр процессора?
Потому, что
передавался указатель на эту локальную структуру.
Как ты себе представляешь указатель на переменную в регистре?
Никак? Тогда как ты представляешь себе передачу указателя, который невозможен?
Помогу тебе разрешить этот ребус. Переменная, на которую существует используемый (про неиспользуемый компилятор выдаст предупреждение) указатель, будет существовать в памяти даже при оптимизации. Иначе нельзя гарантировать валидность указателя даже в однопоточном приложении.
Так в том то и дело,что все эти глюки проявлялись даже если дополнительный поток один, а главный ожидает его завершения, здесь ничего синхронизировать даже не нужно. К тому же если работают несколько потоков, то они пишут в непересекающиеся адреса блока, место под который выделялось оператором new в главном потоке и указатель на него передавался в вспомогательные. Может глюк заключался в другом, сейчас приведу описание:
1. Есть ГЛОБАЛЬНАЯ переменная класса (C)
2. В этом классе выделяется место под блок
3. В одном из методов создается новый поток, которому в передается указатель на этот класс, и происходит ожидание завершения работы.
4. В основной функции потока происходит вызов другого метода тогоже класса по переданному указателю, в котором и осуществлялась запись в блок.
При такой схеме, иногда оказывалось, что в блок ничего не писалось или писалась какая-то белеберда. Исправилось это все, если только в функции потока не использовать переданный указатель, а непосредственно обращаться к переменной класса.
М-да... запутанный код. Видимо, где-то что-то наводится....
И насчет локальной переменной: часть параметров передавалось через указатель на локальную структуру в функции, где создавался доп. поток, при этом опять же таки значения по этому указателю в потоке оказывались далеки от истенных (опять же не всегда). Исправилось объявлением этой структуры как глобальной. Может это конечно все совпадения, но тем не менее, факт есть факт.
На счет фактов. Наш сосед, старенький такой дядечка, не курит и не пьет. Не то что бы совсем... Бывает иногда затенется, когда выпьет, но пьет он очень редко. Помниться затянулся выпил он однажды по-молодости, курнул... а в штатах застрелили Кенеди. В следующий раз это совпало с убийством Ленона. Может это конечно все совпадения, но тем не менее, факт есть факт. Сосед с тех пор не курит... не то что бы совсем... :)
Перевожу: для того, чтобы указать, что переменная может быть изменена извне (относительно потока).
Остальная информация в MSDN отвечает на вопросы "как" и "почему", а не "зачем".
Потому, что
Как ты себе представляешь указатель на переменную в регистре?
Никак? Тогда как ты представляешь себе передачу указателя, который невозможен?
Помогу тебе разрешить этот ребус. Переменная, на которую существует используемый (про неиспользуемый компилятор выдаст предупреждение) указатель, будет существовать в памяти даже при оптимизации. Иначе нельзя гарантировать валидность указателя даже в однопоточном приложении.
М-да... запутанный код. Видимо, где-то что-то наводится....
На счет фактов. Наш сосед, старенький такой дядечка, не курит и не пьет. Не то что бы совсем... Бывает иногда затенется, когда выпьет, но пьет он очень редко. Помниться затянулся выпил он однажды по-молодости, курнул... а в штатах застрелили Кенеди. В следующий раз это совпало с убийством Ленона. Может это конечно все совпадения, но тем не менее, факт есть факт. Сосед с тех пор не курит... не то что бы совсем... :)
Конечно насчет лок. переменных все правильно сказано, но я имел ввиду оптимизацию без ссылки (для примера). И в том же МСДН чуть ниже того, что ты написал есть следующее:
Objects declared as volatile are not used in optimizations because their value can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.
Переводить не буду, именно это я и имел ввиду.
Всетаки я думаю,что все эти глюки пришли по-наследству от других программистов...могло что-то записаться скажем в область, где находится указатель...тогда все ясно, по нему уже нельзя ссылаться