Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблема многопоточного доступа к переменной 
:(
    Опции темы
cubereality
Дата 6.2.2007, 21:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 75
Регистрация: 28.6.2005
Где: http://artiom.vyr tosu.com

Репутация: нет
Всего: 1



Всем привет!

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

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

С уважением.
PM MAIL WWW   Вверх
Anikmar
Дата 6.2.2007, 22:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: нет
Всего: 59



А если в самом классе создать метод (учитывая реентерабельность) по изменению этой переменной не получится?
PM MAIL ICQ   Вверх
cubereality
Дата 6.2.2007, 22:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 75
Регистрация: 28.6.2005
Где: http://artiom.vyr tosu.com

Репутация: нет
Всего: 1



А поподробнее можно о реентерабельности?

Добавлено @ 22:21 
С++ чистый WinAPI.

Скажем мне нужно запретить одновременный доступ к переменной класса, но для каждого созданного объекта отдельно. В смысле чтоб блокирование этой переменной не блокировало изменение этой же переменной в других экземплярах этого класса.
PM MAIL WWW   Вверх
Anikmar
Дата 6.2.2007, 22:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: нет
Всего: 59



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

Грубо говоря перенос критических секций из кода потока в код класса. Для потоков остается вызов метода класса, а этот метод сам предпринимает защитные методы (с помощью тех же критический секций) от одновременного доступа к переменной...
PM MAIL ICQ   Вверх
cubereality
Дата 6.2.2007, 22:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 75
Регистрация: 28.6.2005
Где: http://artiom.vyr tosu.com

Репутация: нет
Всего: 1



А можно конкретный пример кода пожалуйста? В смысле как ЭТО делать?
PM MAIL WWW   Вверх
Anikmar
Дата 6.2.2007, 23:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: нет
Всего: 59



Хм... Я пас - это же теория чисто. Примеров нет, я потоки пару раз использовал, но не в таком ключе.
Просто сама идея: запихать критическую секцию не в функцию потока, а в метод класса. Есть объект, есть потоки. Поток вызывает метод объекта, который должен изменить переменную. Так пусть класс сам думает о критической составляющей...
PM MAIL ICQ   Вверх
cubereality
Дата 7.2.2007, 00:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 75
Регистрация: 28.6.2005
Где: http://artiom.vyr tosu.com

Репутация: нет
Всего: 1



И в таком случае будет защищатся адрес памяти а не условный участок исходного кода?
PM MAIL WWW   Вверх
Anikmar
Дата 7.2.2007, 00:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: нет
Всего: 59



Цитата(cubereality @  6.2.2007,  22:15 Найти цитируемый пост)
Скажем мне нужно запретить одновременный доступ к переменной класса, но для каждого созданного объекта отдельно. В смысле чтоб блокирование этой переменной не блокировало изменение этой же переменной в других экземплярах этого класса. 

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

Цитата(cubereality @  7.2.2007,  00:11 Найти цитируемый пост)
И в таком случае будет защищатся адрес памяти а не условный участок исходного кода? 

А вам что конкретно надо блокировать? Я не слышал, чтобы нужно было блокировать код. Обычно блокируется область памяти для исключения одновременного к ней доступа. Существуют критические секции, недопускающие прерывать код, но не для его защаиты, а чтобы он (код) смог нормально поменять данные.

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


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


Это сообщение отредактировал(а) Anikmar - 7.2.2007, 00:32
PM MAIL ICQ   Вверх
cubereality
Дата 7.2.2007, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 75
Регистрация: 28.6.2005
Где: http://artiom.vyr tosu.com

Репутация: нет
Всего: 1



Неа, переменная автоматическая, в пределах видимости для каждого объекта по отдельности.  Значит можно использовать одну и ту же критическую секцию?

Это сообщение отредактировал(а) cubereality - 7.2.2007, 09:18
PM MAIL WWW   Вверх
SergeCpp
Дата 7.2.2007, 10:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


 
**


Профиль
Группа: Участник
Сообщений: 955
Регистрация: 8.8.2005
Где: At Home

Репутация: 10
Всего: 124



Рекомендую воспользоваться семейством функций Interlocked*

Некоторые из них отражены в Visual C++ Intrinsics

PM MAIL WWW ICQ   Вверх
Earnest
Дата 8.2.2007, 20:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Если переменная не длинее DWORD, то проще использовать InterlockedXXX, как было сказано. Для более сложных данных делаем так:
1) В классе заводим переменную CRITICAL_SECTION (это самый простой и быстрый объект синхронизации)
2) В конструкторе класса ее инициализируем (InitializeCriticalSection)
3) Пишем методы Get и Set, в начале каждого EnterCriticalSection, в конце LeaveCriticalSection
4) В методе Get то, что хотим вернуть (скажем, 5й сверху элемент чего-нибудь) между вызовами Enter\Leave копируем во временную переменную, в конце функции - возвращаем эту временную переменную.
5) Естественно при этом нельзя возвращать указатели\ссылки на защищаемые данные, иначе вся защита псу под хвост.
6) Удобно сделать класс-обертку для методов Enter\Leave (конструктор входит в критическую секцию, деструктор - освобождает ее). Это позволяет обойтись одним вызовом, получить exception-safe код и обойтись без временных переменных. Что-то вроде:
Код

class CLock
{
public:
   CLock (CRITICAL_SECTION* ps):
       m_ps (ps) { EnterCriticalSection(m_ps); }
   ~CLock() { LeaveCriticalSection (m_ps); }
private:
   CRITICAL_SECTION* m_ps;
};

Можно пойти дальше и написать простенький макрос (чтобы спрятать из контекста ненужные переменные):
Код

#define GUARD_SHARED_DATA(cs)   CLock _lock(&cs);

Тогда:
Код

void CMyClass::SetXXX (...)
{
   GUARD_SHARED_DATA (m_cs);
   // TODO: присваиваем чего хотели
   ...
}



--------------------
...
PM   Вверх
GremlinProg
Дата 8.2.2007, 22:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(cubereality @  6.2.2007,  23:53 Найти цитируемый пост)
объектов планируется до сотни тысяч в памяти

Не советую сразу с головой окунаться в секции во всех объектах для такой задачи. Тут явно видна недоработка модели. На каждый маленький экземпляр класса не должно расходоваться слишком много системных ресурсов. В большинстве случаев, при одновременном обращении к данным, достаточно просто организовать конвеер. К тому же, "запирать" конкретную переменную нужно только в двух случаях. Первый -  при обращении к перераспределяющемуся массиву, списку, и т.п., чтобы просто избежать повторного использования указателя. И второй -  при сложных вычислениях, использующих "смежные", т.е. расшаренные ресурсы, в этом случае есть смысл запирать не сами объекты, где эти вычисления производятся, а только общие ресурсы, да и то, только в том случае, если эти ресурсы могут изменяться в вычислениях. Во всех остальных случаях синхронизация не нужна.


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0568 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.