WWW.ИСХОДНИКИ.РУ cpp.sources.ru
java.sources.ru web.sources.ru soft.sources.ru
jdbc.sources.ru asp.sources.ru api.sources.ru

  Форум на исходниках
  C / C++ / Visual C++
  Многопоточность - совсем запутался :))

СПРОСИТЬ  ОТВЕТИТЬ
профайл | регистрация | faq

Автор Тема:   Многопоточность - совсем запутался :))
alex2808 опубликован 12-02-2002 17:57 MSK   Click Here to See the Profile for alex2808   Click Here to Email alex2808  
Привет!!! Запутался совершенно, в каких случаях и когда надо использовать CSemaphore, СMutex, CCriticalSection, CSingleLock и т.д.
Такая задачка:
DCOM, ЕХЕ-сервер c подключением к БД, клиент.
На клиенте выведена запись с БД. Открываю на клиенте новый поток (AfxBeginThread(ThreadToFind, GetSafeHwnd())) и в нем исполняю ThreadToFind -формирую новый SQL и передаю на сервер (поиск подобных). В это время пролистываю запись. Старый поток еще не доработал а нужно создавать уже новый.
Как здесь раставить все эти причандалья, чтобы они не лезли в одну дырку вместе? :)
Возможно ли снять незаконченный поток ?
А то их может выстроиться хорошенькая очередь...

Может у кого-то есть код, поделитесь :)

Manyak опубликован 12-02-2002 23:06 MSK     Click Here to See the Profile for Manyak  Click Here to Email Manyak     
Я такого не делал, но может кое на что сгожусь.
TerminateThread - убивает поток.
По моему здесь критическая секция могла бы подойти, но поскольку я такого не делал, то это только мои догадки.
alex2808 опубликован 13-02-2002 02:15 MSK     Click Here to See the Profile for alex2808  Click Here to Email alex2808     
Где ставить критику в методе, который создает новый поток, или в функции, которая исполняется в потоке?
Drunkard опубликован 13-02-2002 04:17 MSK     Click Here to See the Profile for Drunkard  Click Here to Email Drunkard     
Когда-то еще в учась в аспирантуре занимался взаимодействием нескольких роботов в одном робототехническом комплексе. Даже разрабатывали язык, для программирования их взаимодействий. Там вовсю применяли все эти хреновины, описывающие взаимодействие параллельных асинхронных процессов. Сожрали на этом жирную собаку. Поэтому сейчас в прогах совершенно спокойно их применяю. Вот методика для мьютекса (взаимноисключающего действия). Типа, чтобы два робота не пытались схватить одну деталь одновременно.

Вот типичный код.
Производишь инициализацию мьютекса в параллельных процессах

Например два процесса А и Б.
А) hMutex=CreateMutex(NULL,FALSE,"MyMutex");// Создаем не занятый, потом кто первый захватит
// Если Mutex уже зарегистрирован тем кто вперед запустился, то он откроется
if(hMutex==NULL) return FALSE; // Не смог создать Mutex, а раз не смог, то и работать незачем

Б) hMutex=CreateMutex(NULL,FALSE,"MyMutex");// Создаем не занятый, потом кто первый захватит
// Если Mutex уже зарегистрирован тем кто вперед запустился, то он откроется
if(hMutex==NULL) return FALSE; // Не смог создать Mutex, а раз не смог, то и работать незачем

Как видишь, код один и тот же.
Теперь, нужно ограничить совместный доступ к ресурсу. Этим ресурсом у меня является функция
прописаная в dll, которую подгружают оба процесса. У тебя может быть доступ к файлу или вообще всяка разна хрень. Код опять, в принципе, один и тот же:

А)
//Здесь может быть начало цикла
dw=WaitForSingleObject(hMutex,0); // Проверим, наш ли Mutex
if((dw==WAIT_OBJECT_0)

Drunkard опубликован 13-02-2002 04:22 MSK     Click Here to See the Profile for Drunkard  Click Here to Email Drunkard     
Сволочь! Не пропускает две вертикальные палки! Ну я их словами опишу :) Вместо "или" должно быть две вертикальных черты.

А)
//Здесь может быть начало цикла
dw=WaitForSingleObject(hMutex,0); // Проверим, наш ли Mutex
if((dw==WAIT_OBJECT_0) "или" (dw==WAIT_ABANDONED)) {// Свободен
DolgojdannajaFunkcija();
// Функцию выполнили, теперь выкидываем палку к чертям!
ReleaseMutex(hMutex);
};
// Здесь может быть конец цикла


Б)
//Здесь может быть начало цикла
dw=WaitForSingleObject(hMutex,0); // Проверим, наш ли Mutex
if((dw==WAIT_OBJECT_0) "или" (dw==WAIT_ABANDONED)) {// Свободен
DolgojdannajaFunkcija();
// Функцию выполнили, теперь выкидываем палку к чертям!
ReleaseMutex(hMutex);
};
// Здесь может быть конец цикла

Т.к. Мьютекс изначально создан свободным, то его захватит тот, кто придет к оператору WaitForSingleObject первым.
Вот и все. Остаются только варианты, вместо нуля можно ставить время и пр. Ну в доках прочтешь. Главное вбей себе в голову, что это очень просто, как видно из приведенного кода. А чтобы понять, представляй мьютекс в качестве эстафетной палочки. У кого она в руке, тот и бежит, остальные стоят и ждут. Как только один прибежал, палка сразу прехвачена другим, а остальные ждут. Изначально никакого порядка перехвата мьютекса (палки) нету и быть не могет, т.к. процессы асинхронные.

x опубликован 13-02-2002 05:38 MSK     Click Here to See the Profile for x  Click Here to Email x     
1.как делать категорически нелбзя
так это убивать потоки с WaitAble functions
кончается это плачевно т.к. нока управление находится в ядре убить его все равно нельзя=только получишь глюки и утечки памяти
2.если потоков много=либо юзай CS =не очень хорошо
либо fibers (nt only) c очередью потоков=идеальный вариант
x опубликован 13-02-2002 05:41 MSK     Click Here to See the Profile for x  Click Here to Email x     
сори=проглючил

либо fibers (nt only) c очередью fibers-ов=идеальный вариант

alex2808 опубликован 13-02-2002 18:23 MSK     Click Here to See the Profile for alex2808  Click Here to Email alex2808     
Вот у меня например есть метод FindSimilar в классе диалога. В нем формируется запрос
и открывается новый поток AfxBeginThread(ThreadToFind, GetSafeHwnd()), в котором выполняется ф-я ThreadToFind, например поток A :). Листаем - опять вызывается метод FindSimilar - открывается поток B, предыдущий поток А до конца еще не доработал.

2Drunkard:
1)Где объявлять hMutex?
2)Насколько я понял - в ф-ии ThreadToFind я должен инициализировать hMutex и там же разграничить доступ к ресурсу DolgojdannajaFunkcija():
3)Когда hMutex==NULL, это значит что его уже кто-то взял, или это чисто перестраховочная проверка?
4)dw=WaitForSingleObject(hMutex,0); // Проверим, наш ли Mutex
Если это не наш мютекс, что случиться? Он просто выйдет из текущего потока, или будет дожидаться, пока занявший мютекс поток не выполнит ReleaseMutex(hMutex)? Как изменится действие если передам параметром вместо 0 (нуля) - INFINITE?
5)Какой цикл для примера подразумевается в надписи (//Здесь может быть начало цикла)?

2x:
Насколько я понял, CS - это критическая секция :)
1) Что я должен ограничить Lock-ом и Unlock-ом, открытие нового потока AfxBeginThread(ThreadToFind, GetSafeHwnd()) или весь метод FindSimilar?
2) Что такое fibers, перевелось как волокно, чем они отличаются от потоков?

Ребята, извините за сумбурность вопросов - но очень хочеться разобраться :)))

x опубликован 14-02-2002 02:21 MSK     Click Here to See the Profile for x  Click Here to Email x     
ты должен ограничить Lock & Unlock
исключительно те места в потоках в которых озможен совместный доступ

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

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

alex2808 опубликован 14-02-2002 15:25 MSK     Click Here to See the Profile for alex2808  Click Here to Email alex2808     
2x:
<<fiber-недоделаный поток который сам не умеет переключаться,т.е. fibers-есть группа потоков переключение между которыми производится ими самими

Как понять сам не умеет переключаться, а в группе переключение между потоками производится ими самими ?
Они же не умеют переключаться?

Drunkard опубликован 14-02-2002 17:46 MSK     Click Here to See the Profile for Drunkard  Click Here to Email Drunkard     
alex2808<
Щас некогда, все подробности - ночью.
tonik опубликован 14-02-2002 23:27 MSK     Click Here to See the Profile for tonik  Click Here to Email tonik     
fiber'ы, т.е. волокна, не поддерживаются ядром Windows, а потому не могут выполняться одновременно - они выполняются в пользовательском потоке и сами переключают управление между собой (функцией SwitchToFiber). Таким образом, программер может реализовать собственный алгоритм переключения между волокнами.
Drunkard опубликован 15-02-2002 01:48 MSK     Click Here to See the Profile for Drunkard  Click Here to Email Drunkard     
Ответы на вопросы по Мьютекс
1) В самом начале WinMain(). HANDLE мьютекса это уникальный объект системы и все процессы которые упоминают его имя, упоминают один и тот же объект.
2)ф-ия ThreadToFind - я такой не знаю
Один раз объявляешь в каждом процессе hMutex=CreateMutex(NULL,FALSE,"MyMutex"); и остальное тебя не дерет. Мьютекс в данном случае свободен, кто первым его подберет, того он и будет сначала.
Естественно HANDLE hMutex должна быть объявлена как глобальная в каждом процессе и имя "MyMutex" должно быть абсолютно одинаковым во всех процессах.
3) Это проверка, т.к. если мьютекс не создан или не открылся, то прога работать будет, но результата тебе никто не гарантирует. Так как процесс у которого hMutex==NULL обязательно без спросу вломится в крит секцию либо всегда будет ее обходить, т.е не выполнит задачу..
4) Если мьютекс не наш, то действие зависит от второго параметра - времени. Если 0, то он сразу уйдет за секцию if и будет выполнять любые другие действия. Если INFINITE, то здесь он и встанет дожидаться пока мьютекс освободится и очччччень на долго. Если задашь время, то он столько подождет, а потом уже в зависимости от мьютекса, либо зайдет в секцию if либо перепрыгнет ее.
5) Ну это цикл для примера, что процесс ходит к этой критической секции неоднократно, вот и всё.

По твоей задаче, однозначно, нужно применять мьютексы. Но так как мьютекс это универсальное средство, т.е. применимое к потокам в одном процессе и к потокам в разных процессах, то можно использовать и средство попроще, являющееся частным случаем мьютекса - Критические секции. Они - это тот же мьютекс, только применимый к потокам в одном процессе. У тебя судя по всему, процесс один, потоков много. Можешь применить Критические секции. Но у них есть один недостаток: нельзя задать время ожидания, как в мьютексе, т.е. при анализе входа в критическую секцию, у них всегда INFINITE. Правда для NT2000 есть функция TryEnterCriticalSection которая проверяет, но не тормозит, но в 95 и 98 она не работает.

Drunkard опубликован 15-02-2002 01:51 MSK     Click Here to See the Profile for Drunkard  Click Here to Email Drunkard     
Привожу тебе полный рабочий код проги, которая использует критические секции для трех потоков. Это просто голый пример.

#include <windowsx.h>
#include <windows.h>
#include <stdio.h>

BOOL Register(HINSTANCE hInst);
BOOL Create(HINSTANCE hInst, int nCmdShow);
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
void _OnDestroy(HWND hwnd);

void Potok1(void);
void Potok2(void);
void Potok3(void);
BOOL Obshaja(char*);

CRITICAL_SECTION cs;

HWND hWnd;
char szWinName[]="Crit";

int WINAPI WinMain (HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpszArgs,int nCmdShow)
{
MSG msg;
DWORD ThId1;
DWORD ThId2;
DWORD ThId3;

InitializeCriticalSection(&cs);

if(!Register(hInst)) return FALSE;
if(!Create(hInst,nCmdShow)) return FALSE;

CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Potok1,NULL,0,&ThId1);
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Potok2,NULL,0,&ThId2);
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Potok3,NULL,0,&ThId3);

while(GetMessage(&msg,NULL,0,0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

BOOL Register(HINSTANCE hInst)
{
WNDCLASS wc1;
memset(&wc1,0,sizeof(WNDCLASS));
wc1.hInstance=hInst;
wc1.lpszClassName=szWinName;
wc1.lpfnWndProc=WindowFunc;
wc1.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wc1.hCursor=LoadCursor(NULL,IDC_ARROW);
wc1.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
return RegisterClass(&wc1);
}

BOOL Create(HINSTANCE hInst, int nCmdShow)
{
HWND hwnd=CreateWindow(szWinName,"Критические дни :)",WS_OVERLAPPEDWINDOW,100,100,300,300,
HWND_DESKTOP,NULL,hInst,NULL);
if(!hwnd) return FALSE;
ShowWindow(hwnd,SW_SHOW);
UpdateWindow(hwnd);
hWnd=hwnd;
return TRUE;
}

void _OnDestroy(HWND hwnd)
{
DeleteCriticalSection(&cs);
PostQuitMessage(0);
}

LRESULT CALLBACK WindowFunc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{ switch(message) {
HANDLE_MSG(hwnd,WM_DESTROY,_OnDestroy);
default: return DefWindowProc(hwnd,message,wParam,lParam);
}
}

void Potok1(void)
{
//Начало крит секции
EnterCriticalSection(&cs);
Obshaja("Первый поток");
//Конец крит секции
LeaveCriticalSection(&cs);
}

void Potok2(void)
{
//Начало крит секции
EnterCriticalSection(&cs);
Obshaja("Второй поток");
//Конец крит секции
LeaveCriticalSection(&cs);
}

void Potok3(void)
{
//Начало крит секции
EnterCriticalSection(&cs);
Obshaja("Третий поток");
//Конец крит секции
LeaveCriticalSection(&cs);
}

BOOL Obshaja(char* sPotok)
{
char Str[100];
sprintf(Str,"Меня использует %s",sPotok);
MessageBox(hWnd,Str,"Критическая функция",MB_OK);
return TRUE;
}

Здесь потоки аккуратно последовательно обращаются к ф-ии Obshaja().
Попробуй закомментарить EnterCriticalSection(&cs); и LeaveCriticalSection(&cs); в потоках и они начнут вламываться в нее без разбору.
Ну, будь здоров! Не кашляй. :)))

alex2808 опубликован 18-02-2002 10:48 MSK     Click Here to See the Profile for alex2808  Click Here to Email alex2808     
Сипасибо, постараюсь не болеть :)
Дело в том, что в моей общей ф-ии исп.
CoInitializeEx. И в хэлпе, по WaitForSingleObject рекомендуют исп. в этом случае MsgWaitForMultipleObjects.
Почему? И чем они отличаются?

СПРОСИТЬ  ОТВЕТИТЬ
Перейти:


E-mail | WWW.ИСХОДНИКИ.RU

Powered by: Ultimate Bulletin Board, Freeware Version 5.10a
Purchase our Licensed Version- which adds many more features!
© Infopop Corporation (formerly Madrona Park, Inc.), 1998 - 2000.