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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Потокозащищенность объектов 
V
    Опции темы
orlangur86
Дата 17.7.2008, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 17.7.2008

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



Доброго времени суток всем форумчанам!
Может быть данная тема уже поднималась и на форуме уже есть ответы на мои вопросы - что ж, тогда прошу простить, плохо искал (искал - это факт, но может не по тем ключевым словам)
и был бы благодарен за ссылку на соответствующую ветку форума.

Собственно проблема. Существует класс (пусть будет класс А) для работы в сети (ну скажем фтп-клиент), есть другой класс ( класс Б), который использует вышеуказаный сетевой компонент в своих целях.
есть необходимость работы класса Б паралельно. Т.е. необходимо использовать потоки. Потоки вначале были реализованы на базе класса QThread (Qt lib) в виде: класс Б наследует от QThread и реализует метод обработки, за тем на базе того же QThread но это уже был отдельный класс, которому передавался указатель на Б, и тот уже при запуске вызывал обработку Б.
Так же пробовал реализовать на базе Thread из библиотеки POCO (portable components). Создание объектов потока и класса Б происходит следующим образом.
в основной программе: 
1) обрабатывается командная строка
2) определяется число необходимых потоков
3) в цикле происходит:
   - создание объекта Б (динамически через new)
        - в конструкторе Б происходит создание объекта А (так же через new) и указатель на А сохраняется как private член класса (не static)
  - прочие настройки (не существенные для данного вопроса)
  - создание объекта потока с передачей в конструктор в качестве параметра, указатель на Б
  - запуск потока
4) join для всех потоков.

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

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

помогите советом, кто может! smile
заранее благодарю
PM MAIL   Вверх
Lycifer
Дата 17.7.2008, 11:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 144
Регистрация: 4.11.2007

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



ТЫ используешь одну и туже память(у тебя должен быть кон7структор копирывания)
PM MAIL ICQ   Вверх
EnergoHokum
Дата 17.7.2008, 11:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 600
Регистрация: 10.11.2006
Где: Россия, Ставропол ь

Репутация: 3
Всего: 6



Опиши подробнее, как ты формируешь логи. Кажется мне, всё дело в них.
PM MAIL ICQ   Вверх
orlangur86
Дата 17.7.2008, 11:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 17.7.2008

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



Lycifer,  это как же я использую одну и ту же память если в тестовом отладочном варианте для 3-х потоков я создаю 3 объекта класса Б (как я уже писал при помощи new) и в конструкторе каждого объекта Б вызывается конструктор А (так же при помощи new)


EnergoHokum, логи формируются следующим образом:
в отладочном варианте и конструктор класса А и конструктор класса Б принимает доп параметр - число (ну в частности просто порядковый номер потока от 0 до 2 в отладочном случае)
в конструкторе А создается файл (при помощи std::fstream класса) с именем some_name_<число которое передано в конструктор>.log
при выполнении какого-либо метода А в лог записывается следующая информация: <число для отладки> <this приведеное к unsigned> <GetCurrentThreadId()> ну инфа по методу всякая

и вот что число для отладки, что this имеют одно и то же значение (ну логично в принципе), но вот ID потока разный. причем такой микс во всех 3-х потоках, во всех 3-х лог-файлах, которые создаются... я в замешательстве
PM MAIL   Вверх
Lazin
Дата 17.7.2008, 12:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



Цитата(orlangur86 @  17.7.2008,  11:01 Найти цитируемый пост)
Предполагается, что каждый поток пользуется своей копией Б, и своей копией А. Проблема возникает в том, что судя по логам, которые записываются при обращении к методам объекта класса А, этот объект вызывается как из родного потока, для которого он был создан, так и из чужих потоков, что недопустимо и в результате получается полный бред без всякой логики работы.

покажи конструктор копирования класса В

Добавлено через 1 минуту и 20 секунд
и конструктор класса В, и как создаешь и передаешь данные в потоки
PM MAIL Skype GTalk   Вверх
orlangur86
Дата 17.7.2008, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 17.7.2008

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



конструкторы копирования для А и для Б нигде не исопльзуются. даже в неявном виде. в одном месте происходит создание Б при помощи new, и в одном месте происходит удаление Б
та же фигня и для А

Класс Б объявлен примерно так:

Код

class classB{
 private:
  classA *obj;
 public:
classB(int debug_val=0);
virtual ~classB();
 ....
void process(); //метод с полезной нагрузкой
};


Вот его конструктор и деструктор

Код

classB::classB(int debug_val)
{
  obj=new classA(debug_val);
}

classB::~classB()
{
 delete obj;
}


Создание потоков и передача в них данных:

в последней переделке/реализации сделано через POCO (portable Components) и их реализацию потоков.

т.е.
Код

class ThreadItem: public Runnable
{
 private:
 classA *member;
 public:
 ThreadItem(classA *a)
 {
   member=a;
 }
 virtual ~ThreadItem()
 {
  delete member;
 }
 virtual void run()
 {
   member->process();
 }
}

в main'е все происходит примерно следующим образом

Код

...
int count_of_threads=3; //ну для отладки просто 3 потока
vector<ThreadItem *> runs;
vector<Thread *> threads; //Thread - класс из POCO

for(int i=0;i<count_of_threads;++i)
{
  classA *ca=new classA(i); // тут передача того самого отладочного числа, номера потока
  ThreadItem *ti=new ThreadItem(ca);
  runs.push_back(ti);
  Thread *t=new Thread();
  threads.push_back(t);
 t->start(ti);
}

for(int i=0;i<count_of_threads;++i)
{
 threads[i]->join();
 delete threads[i];
 delete runs[i];
}
...



примерно так.
PM MAIL   Вверх
Lazin
Дата 17.7.2008, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



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

Добавлено @ 12:59
кстати объекты у тебя создаются в одном потоке, но методы run должны вызываться из разных потоков...
если тебе нужно, что-бы объекты создавались в разных потоках, добавь код по созданию объекта в код самого потока, пускай поток сам управляет своими данными...

Код

class ThreadItem: public Runnable
{
 int ctor_data;
 boost::shared_ptr<classA> member;
 public:
 ThreadItem(int data) : Runable(), ctor_data (data), member()
 {
 }

 virtual ~ThreadItem()
 {
 }

 virtual void run()
 {
   //создаем объект принадлежащий потоку
   member = boost::shared_ptr<classA>( new classA(ctor_data) );
   member->process();
 }
};


Это сообщение отредактировал(а) Lazin - 17.7.2008, 13:00
PM MAIL Skype GTalk   Вверх
orlangur86
Дата 17.7.2008, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 17.7.2008

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



хз...

Код

using namespace std;
classB
{
 private:
  int debug_val;
  fstream log;
  classB(int dv)  
 {
    char buf[5];
    string logname="classb_log_";
    logname+=itoa(dv,buf,10);
   logname+=".log";
    log.open(logname,ios::out);
   debug_val=dv;
  }
 virtual ~classB()
 {
   log.flush();
   log.close();
 }
 
void  method1()
 {
   log<<debug_val<<" "<<((unsigned)this)<<" "<<GetCurrentThreadId()<<" some other method1 info\r\n";
 }
void  method2()
 {
   log<<debug_val<<" "<<((unsigned)this)<<" "<<GetCurrentThreadId()<<" some other method2 info\r\n";
 }
};


ну и как я уже писал: GetCurrentThreadId() на этом месте встречаются 3 разных значения в разных строках лога
PM MAIL   Вверх
Lazin
Дата 17.7.2008, 13:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



в main теперь все проще:

Код

...
for(int i=0;i<count_of_threads;++i)
{
  ThreadItem *ti=new ThreadItem(i);
  runs.push_back(ti);
}
...


Добавлено через 2 минуты и 5 секунд
Цитата(orlangur86 @  17.7.2008,  13:01 Найти цитируемый пост)
ну и как я уже писал: GetCurrentThreadId() на этом месте встречаются 3 разных значения в разных строках лога 

ты уверен что у тебя вызывается метод одного объекта из разных потоков, а не один и тот-же метод разных объектов из разных потоков
PM MAIL Skype GTalk   Вверх
orlangur86
Дата 17.7.2008, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 17.7.2008

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



Цитата(Lazin @ 17.7.2008,  13:02)
Цитата(orlangur86 @  17.7.2008,  13:01 Найти цитируемый пост)
ну и как я уже писал: GetCurrentThreadId() на этом месте встречаются 3 разных значения в разных строках лога 

ты уверен что у тебя вызывается метод одного объекта из разных потоков, а не один и тот-же метод разных объектов из разных потоков

ну да... дело в том, что отладочное число и адрес this для одного лог-файла - одни  и те же, а вот ИД потоков разные

на счет более простого кода в main - да, наверное так действительно проще, но и в моем варианте ничего противозаконного нету (это я к тому, что и там должны пахать нормально потоки... но не пашут...)
PM MAIL   Вверх
orlangur86
Дата 18.7.2008, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 17.7.2008

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



Спасибо всем, кто откликнулся!
Проблема как всегда в драйвере прямых рук ))
Один из ресурсов, который передавался классу Б в момент его инициализации, не был ни продублирован для каждого потока отдельно, и не был потоко-безопасным
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "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.0540 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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