class Test
{
public:
Test(unsigned char inObjId):mThrHandle(NULL), mObjId(inObjId){}
~Test()
{
//...
}
// Активация потока
bool start()
{
mThrHandle=CreateThread(NULL,
NULL,
_threadstart, //Статический "запускальщик" функции обработки потока
this, //Параметр статической функции, указатель на объект
NULL,
NULL);
return true;
}
unsigned char mObjId; //Идентификатор объекта
protected:
HANDLE mThrHandle;
static __stdcall DWORD _threadstart(void* param)
{
static_cast<Test*>(param)->[color="green"]myFunc()[/color]; [color="red"]//Вот не будет ли искажаться переменная param при одновременном обращении нескольких объектов из разных потоков?[/color]
return 0;
}
//Метод объекта
void [color="green"]myFunc()[/color]
{
for(;;)
{
cout << mObjId << endl; //Выводим ID объекта
Sleep(1000);
}
}
};
C++ параллельные потоки
Для того, чтобы реализовать процедуру потока в качестве члена класса, нужно создать статическую функцию обработчик, которая в свою очередь уже будет запускать индивидуальную функцию обработки для каждого из созданных объектов класса.
Меня смущает момент доступа нескольких объектов к статической функции, из параллельных потоков. Не может ли тут возникнуть конфликта? Что нужно предпринять, во избежании?
Конфликт может возникнуть если одновременно к одним и тем же данным будет доступ. Если в ф-ции будут использоваться локальные переменные, то при каждом вызове они будут создаваться свои и это не помешает.
Цитата: oxotnik333
Конфликт может возникнуть если одновременно к одним и тем же данным будет доступ. Если в ф-ции будут использоваться локальные переменные, то при каждом вызове они будут создаваться свои и это не помешает.
Дело в том, что в статическую функцию мы уже передаем данные, а именно указатель на объект, который в статической функции запускает свой локальный метод.
Что то типа
Код:
Ведь в случае статической функции, все ее переменные для всех экземпляров класса будут общими? В т.ч. и параметры?
______________________
Кажется я туплю... _threadstart будет запускаться ведь последовательно из одного потока... Т.е. поочередно и безконфликтно... ?
Цитата: Gigahard
Ведь в случае статической функции, все ее переменные для всех экземпляров класса будут общими? В т.ч. и параметры?
Параметры передаются через стек/регистры. У каждого потока свой стек и регистры.
Они будут одинаковыми если их задать таковыми.
[/COLOR]
Потом посмотрел, да она ж в основном потоке только один раз для каждого объекта вызывается, да итого последовательно, а значит безконфликтно.
В общем, опасаться стоит только в случае обращения к статическим членам класса или к глобальным данным из разных потоков, а так вроде все нормалек получается :)
Вот возник вопрос, если объект создан в основном потоке, а обращение к его методам идет из дополнительного потока, то это как межпотоковый обмен получается? Или методы объекта запускаясь в дополнительном потоке изолированы от основного?
Поток в виндовс - это "единичка исполнения", независимый "конвейер" команд, кидающий их процессору со своим личным контекстом.
Контекст - это системная информация о процесе, в ней хранится указатель на код, который поток сейчас выполняет, его стек (очень упростил) и регистры. Это личная информация потока. Все остальное - общее.
Вот пример:
Код:
...
int a=1;
void f(int* i) { int b=0; ++(*i); }
void g(int k) { int b=0; ++k; }
thread1.start( f, &a ); // поток запустится и вызовет f(&a);
thread2.start( f, &a );
thread3.start( g, a );
int a=1;
void f(int* i) { int b=0; ++(*i); }
void g(int k) { int b=0; ++k; }
thread1.start( f, &a ); // поток запустится и вызовет f(&a);
thread2.start( f, &a );
thread3.start( g, a );
В результате выполнения такго кода создается 2 потока, все два параллельно бегут-бегут-бегут-бегут и забегают в одну и ту же функцию f(int* ), которая получает указатель на расположенную в памяти процесса переменную а. Так как адресное пространство общее, то каждый поток будет увеличивать на 1 одну и ту же ячейку общего адресного пространства. Вероятно, после выполнения такого кода значение переменной а будет увеличено два раза.
Внутри одной и той же функции f один и тот же код в двух потоках создает локальную переменную b. Она создается в стеке. Стек (очень приблженно) для каждого потока свой, индивидуальный. Соответственно, переменная b для каждого потока будет своя.
Третий поток принимает целое "по значению", то есть сздает свою локальную копию передаваемых ему данных. В стеке. И меняет свою личную копию, не оказывая влияния на общие данные.
Цитата:
Вероятно, после выполнения такого кода значение переменной а будет увеличено два раза.
Если для вашей задачи формулировка "этот код в зависимости от случайных обстоятельств может увеличить значение переменной на 2, а может и не увеличить его на 2, или увеличить, но не на два..." недопустима (например, не устраивает заказчика системы наведения ракет на луну), то следует задуматься о синхронизации между потоками при обращении к общим данным, чтобы ничего не повредить.
Код:
class Test
{
Test(): mVar(0)
void write()
{
//что то периодически пишем в mVar
}
unsigned int read()
{
//что то периодически читаем из mVar
}
protected:
unsigned int mVar;
};
Test obj;
thread.start(&obj) //Внутри потока запускается obj->write();
//В основном потоке
obj.read();
{
Test(): mVar(0)
void write()
{
//что то периодически пишем в mVar
}
unsigned int read()
{
//что то периодически читаем из mVar
}
protected:
unsigned int mVar;
};
Test obj;
thread.start(&obj) //Внутри потока запускается obj->write();
//В основном потоке
obj.read();
Вот случай, когда в основном потоке создается объект класса. Далее создается доп. поток, которому передается указатель на объект. Поток в свою очередь запускает метод объекта, обращаясь к его внутренним переменным.
Ну и из основного потока мы тоже запускаем метод доступа обращающийся к переменной объекта...
В данном случае для обоих потоков переменная объекта mVar является общей и доступ к ней нужно оформлять через CriticalSection или же нет?
Цитата: Gigahard
В данном случае для обоих потоков переменная объекта mVar является общей и доступ к ней нужно оформлять через CriticalSection или же нет?
если общая, то надо синхронизировать
Да, вот я как бы и спрашиваю - в данном случае общая или нет? :)
ну сам то подумай: экземпляр класса один создается, соотв. внутренний член тоже в единственном экземпляре будет.