Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Проблема многопоточного доступа к переменной

504
06 февраля 2007 года
lexluther
71 / / 26.10.2004
Всем привет!

Помогите пожалуйста решить следующую проблему:

У меня есть некий класс A который имеет некую переменную B. Я создаю N таких объектов в памяти, и потом из двух или более разных потоков (многозадачность) меняю вышеупомянутую переменную в каждом конкретном объекте по разному и в разное время. Проблема в том что мне НЕЛЬЗЯ чтобы к этой переменной в одном отдельно взятом созданном в памяти объекте мог получить доступ более чем один поток одновременно. В теории это можно решить при помощи создания отдельного объекта CRYTICAL_SECTION для каждого созданного экземпляра класса и защитой этой критической секцией метода присвоения переменной значения. Но объектов планируется до сотни тысяч в памяти. Как мне поступить в этом случае?

С уважением.
504
06 февраля 2007 года
lexluther
71 / / 26.10.2004
С++ чистый WinAPI.

Скажем мне нужно запретить одновременный доступ к переменной класса, но для каждого созданного объекта отдельно. В смысле чтоб блокирование этой переменной не блокировало изменение этой же переменной в других экземплярах этого класса.
355
06 февраля 2007 года
<SCORP>
786 / / 21.10.2006
помоему, без стандартных объектов синхронизации никак. на выбор -- критические секции, мьютексы, семафоры, события
18K
06 февраля 2007 года
max_br
34 / / 10.12.2006
можно попробовать остоновить все потоки кроме текущего,внести изменения и запустить снова.

можно сделать следующим методом(выдрал из статьи не проверял)

Код:
Procedure StopThreads;
var
h,CurrTh,ThrHandle,CurrPr:thandle;
Thread:TThreadEntry32;
begin
CurrTh:=GetCurrentThreadId;
CurrPr:=GetCurrentProcessId;
h:=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
if hINVALID_HANDLE_VALUE then
begin
Thread.dwSize:=SizeOf(TThreadEntry32);
if Thread32First(h,Thread) then
repeat
if (Thread.th32ThreadIDCurrTh)and(Thread.th32OwnerProcessID=CurrPr) then
begin
ThrHandle:=OpenThread(THREAD_SUSPEND_RESUME,false,Thread.th32ThreadID);
if ThrHandle>0 then
begin
SuspendThread(ThrHandle);
CloseHandle(ThrHandle);
end;
end;
until not Thread32Next(h,Thread);
CloseHandle(h);
end;
end;

Procedure RunThreads;
var
h,CurrTh,ThrHandle,CurrPr:thandle;
Thread:TThreadEntry32;
begin
CurrTh:=GetCurrentThreadId;
CurrPr:=GetCurrentProcessId;
h:=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
if hINVALID_HANDLE_VALUE then
begin
Thread.dwSize:=SizeOf(TThreadEntry32);
if Thread32First(h,Thread) then
repeat
if (Thread.th32ThreadIDCurrTh)and(Thread.th32OwnerProcessID=CurrPr) then
begin
ThrHandle:=OpenThread(THREAD_SUSPEND_RESUME,false,Thread.th32ThreadID);
if ThrHandle>0 then
begin
ResumeThread(ThrHandle);
CloseHandle(ThrHandle);
end;
end;
until not Thread32Next(h,Thread);
CloseHandle(h);
end;
end;
355
06 февраля 2007 года
<SCORP>
786 / / 21.10.2006
не думаю, что это оптимальный вариант. ведь пока один объект занят, другие потоки могут работать с остальными объектами. а там получается, что в любой момент времени работает только один поток. т.е. по факту никакой многопоточности и нет
504
06 февраля 2007 года
lexluther
71 / / 26.10.2004
[QUOTE=<SCORP>;172325]помоему, без стандартных объектов синхронизации никак. на выбор -- критические секции, мьютексы, семафоры, события[/QUOTE]

Так они защитят участок памяти? Или условный участок кода? Вот что я понять не могу
361
07 февраля 2007 года
Odissey_
661 / / 19.09.2006
=) если этот участок кода организует обращение к памяти, то они защищают и обращение к памяти.
В линухе можно использовать sig_atomic, но есть один недостаток - у нее значение типа int. В винде помоему тоже есть что-то связанное с atomic - гарантирующее отсутствие одновременного обращения из двух процессов/потоков (точнее даже - гарантия того что операция присваивания/чтения значения этой переменной займет не более одного такта).
А вообще в стандарте C++09 таки обещают этот тип "леголизовать" официальным термом - atomic. (Ура товарищи!!!)

То есть, если переменная типа int - ищите в сторону atomic, а если нет -используйте критическую секцию (незабудьте прочитать перед этим про состояние "гонок", дедлоки... ).

Цитата:
В теории это можно решить при помощи создания отдельного объекта CRYTICAL_SECTION для каждого созданного экземпляра класса


Добавляй прямо в метод.

18K
07 февраля 2007 года
max_br
34 / / 10.12.2006
Цитата:

не думаю, что это оптимальный вариант. ведь пока один объект занят, другие потоки могут работать с остальными объектами. а там получается, что в любой момент времени работает только один поток. т.е. по факту никакой многопоточности и нет


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

Можно попробывать тормозить только те потоки которые пытаються получить доступ к уже изменяемым данным.
Перед изменением выставляеш какой нить флаг. Далее если флаг выставлен приостанавливаеш текущий поток. После изменений снимаеш флаг и запускаеш приостановленные потоки.

3
07 февраля 2007 года
Green
4.8K / / 20.01.2000
Останавливать потоки - это неправильный метод, опасный метод, ну и глупый метод!

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

Теперь к сути топика.
Для решения проблемы нужно блокировать конкретные объекты, но это накладно в силу их количества. Можно блокировать все объекты, но это сильно снижает производительность. Берем промежуточное решение: разбиваем объекты на логические блоки и блокируем блоками.

Но это все лечение симптомов, а не болезни. Проблема здесь значительно глубже.
lexluther, ты уверен, что тебе необходимо такое огромное количество объектов? Ты уверен, что у всех потоков должен быть доступ ко всему простанству этих объектов? Ты уверен, что все потоки должны читать и писать в это пространство?

Я вот почти уверен в обратном: если пересмотреть архитектуру и принцип взаимодействия можно отказаться от всех вышеобозначенных сложностей.
1.8K
07 февраля 2007 года
k3Eahn
365 / / 19.12.2005
У MS уже давно есть набор API для таких случаев (правда, судя по описанию, там есть кое-какие ограничения):
Interlocked Variable Access
18K
07 февраля 2007 года
max_br
34 / / 10.12.2006
Цитата:

Останавливать потоки - это неправильный метод, опасный метод, ну и глупый метод!



А можна поподробнее. Хотябы буду знать в чем глуп.

3
07 февраля 2007 года
Green
4.8K / / 20.01.2000
Метод глуп потому, что останавливать ты собираешься ВСЕ потоки, даже те, которые не имеют никакого отношения к проблеме синхронизации. Теряются всякие преимущества мультипотоковости. Кроме того запуск и остановка потока процессы не мгновенные, потоэтому программа будет работать значительными урывками. А теперь представь, как это будет выглядеть для пользователя графического интерфейса.

Метод опасен потому, что опять же остановка и запуск потоков не происходят мгновенно и не атомарно. Кроме того между снятием снапшота и остановкой потоков из этого снепшота, можно насоздавать такое огромное множество новых потоков, что вся эта схема сходит на нет. Но самое вероятное, что пока один поток останавливает другие, его остановят самого и всё... приложение встало (deadlock). Кроме того, ка ты будешь отличать потоки остановленные твоим механизмом и остановленные по другим причинам?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог