Потоки. Waitforsingleobject.

  • Автор темы sanya923
  • Дата начала
S

sanya923

Гость
#1
Здравствуйте!
Помогите пожалуйста решить проблему.
Читать лучше сразу самый низ кода - большой комент, там в принципе вся проблема и заключена.

C++:
// spo1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include "windows.h"
#include "stdlib.h"
#include "stdio.h"
#include <string>
using namespace std;

class TQuery
{
/*только public оставил на свое усмотрение*/
public:
static TQuery *head,*tail;
static int count_query,count_obs;
int p,v,i;
TQuery *next,*pre;
TQuery(int p_, int v_, int i_) : p(p_), v(v_), i(i_), next(NULL), pre(NULL)
{}
//добавление элемента в очередь
void Past(TQuery *q)
{
count_query+=1;
TQuery *poisk;
poisk=head;
if (tail == NULL)
{
tail=q;
head=q;
}
else
{
if (q->p>poisk->p)
{
poisk->pre=q;
q->next=poisk;
head=q;
}
else
{
if (poisk->next==NULL)
{
q->pre=poisk;
poisk->next=q;
tail=q;
}
else
{
while ((q->p<=poisk->p)&&(poisk->next!=NULL))
poisk=poisk->next;
if (q->p==poisk->p)
{
poisk->next=q;
q->pre=poisk;
tail=q;
}
else
{
q->pre=poisk->pre;
poisk->pre->next=q;
poisk->pre=q;
q->next=poisk;
}
}
}
}
}
//удаление элемента из очереди
void UdElm()
{
TQuery *ud;
count_obs+=1;
count_query-=1;
if (head->next!=NULL) 
{
head=head->next;
head->pre->next=NULL;
}
else
{
StartClear();
}
delete ud;
}
//обнуление параметров
void StartClear()
{head=NULL;tail=NULL;count_query=0;}
void ObsClear()
{count_obs=0;}
};

HANDLE sp; //для семафора
HANDLE s_kanal[3]; //для семафоров
HANDLE uvv[3]; //для устройст(потоков) обслуживающих заявки
HANDLE a,b; //а-поток поступающих заявок,b-поток опрашивающий устройства
bool p_kanal[3]; //признак занятости устройства
TQuery *q_elm_kanal[3]; //для обслуживающихся заявок

//поток с поступающими заявками
int fThread1()
{
int i=0;
double p_,v_,t1;
TQuery *z;
while (true)
{
WaitForSingleObject(sp,INFINITE);
i+=1;
p_=rand(); v_=rand(); p_=p_/32768; v_=v_/32678;
z = new TQuery(unsigned(20*p_+0.5),unsigned(8*v_+0.5),i);
z->Past(z);
cout<<"заявка № "<<i<<" встала в очередь (приоритет "<<z->p<<", объем "<<z->v<<", № "<<z->i<<")"<<endl;
ReleaseSemaphore(sp,1,NULL);
t1=rand();
t1=t1/32678;
t1=1000+2000*t1;
Sleep(unsigned(t1));
}
return 0;
}

//поток обслуживающего устройства(три устройства будет)
int fThread2(int i_)
{
double t2;
while (true)
{
WaitForSingleObject(s_kanal[i_],INFINITE);//-------здесь поток виснет--------
t2=rand(); t2=t2/32678; t2=1000*i_+1000*q_elm_kanal[i_]->v;
Sleep(unsigned(t2));
cout<<"  устройство № "<<i_<<" обслужило заявку № "<<q_elm_kanal[i_]->i<<" за "<<unsigned(t2)<<endl;
p_kanal[i_]=true;
}
return 0;
}

//поток опрашивающий устройства
int fThread3()
{
int i;
while (true)
{
if (TQuery::count_query!=0)
{
for (i=0;i<3;i++)
{
WaitForSingleObject(sp,INFINITE);
if (p_kanal[i])
{
p_kanal[i]=false;
q_elm_kanal[i]=TQuery::head;
TQuery::UdElm;
cout<<"  заявка № "<<q_elm_kanal[i]->i<<" поступила на устройство № "<<i<<endl;
ReleaseSemaphore(s_kanal[i],1,NULL);
ReleaseSemaphore(sp,1,NULL);
break;
}
ReleaseSemaphore(sp,1,NULL);
}
}
}
return 0;
}

int TQuery::count_obs;
int TQuery::count_query;
TQuery * TQuery::head;
TQuery * TQuery::tail;

int main()
{
TQuery::StartClear; TQuery::ObsClear;
//поток с поступающими заявками сразу начинает работать поэтому 1
sp=CreateSemaphore(NULL,1,1,NULL);
int i;
for (i=0;i<3;i++)
{
/*когда потоки устройств запускаются они должны ждать,
поэтому 0 поставил*/
s_kanal[i]=CreateSemaphore(NULL,0,1,NULL);
p_kanal[i]=true;
}
a=CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)fThread1,NULL,NULL,NULL);
for (i=0;i<3;i++)
{
/*здесь виснет при первом заходе(см. fThread2)
и на второй круг не идет, ну и следовательно и "b" тоже не запускается,
а в нем как раз ReleaseSemaphore, который должен просигнализировать.
поток "a" при этом продолжает работать.
в делфи писал, всё было норм. хотел разобраться с этим же и в с++.
думается я с потоками где-то налажал, неже ли с семафорами,
т.к. в делфи для синхронизации также пользовался API, т.е. CreateSemaphore,
WaitForSingleObject,ReleaseSemaphore, а вот поток создавал подругому, не с
помощью CreateThread*/
uvv[i]=CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)fThread2(i),NULL,NULL,NULL);
}
b=CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)fThread3,NULL,NULL,NULL);
return 0;
}
 

lazybiz

Well-Known Member
03.11.2010
1 339
0
#2
Для потока точка входа определена как:
C++:
DWORD WINAPI ThreadProc( __in LPVOID lpParameter );
если хочешь передать параметры в поток, передавай их через...
C++:
HANDLE WINAPI CreateThread(
__in_opt  LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in	  SIZE_T dwStackSize,
__in	  LPTHREAD_START_ROUTINE lpStartAddress,
__in_opt  LPVOID lpParameter, <------------------------- вот этот параметр !!!
__in	  DWORD dwCreationFlags,
__out_opt LPDWORD lpThreadId
);
Это: uvv=CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)fThread2(i),NULL,NULL,NULL);
бред, вообще непонятно как это может работать. Переменную i передавай заместо 3-го NULL с конца.

Тут: b=CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)fThread3,NULL,NULL,NULL);
та же лажа только в профиль. Функция fThread3 не принимает параметров, хотя должна.


fThread1, fThread2 и fThread3 должны быть определены как:
DWORD WINAPI fThread1( LPVOID lpParameter )
DWORD WINAPI fThread2( LPVOID lpParameter )
и
DWORD WINAPI fThread3( LPVOID lpParameter )
соответственно.

Переписывай.
 
S

sanya923

Гость
#3
lazybiz, спасибо за совет.
Я попробовал исправить, но у меня чет как-то не вышло. Решил упростить задачу:
C++:
#include "stdafx.h"
#include <iostream>
#include "windows.h"
using namespace std;

HANDLE h1,h2;
HANDLE sp1;

DWORD WINAPI Thread1(LPVOID lpParam1)
{
for (int i=0;i<100;i++)
{

WaitForSingleObject(sp1,INFINITE);
cout<<"Potok "<<1<<endl;
ReleaseSemaphore(sp1,1,NULL);
Sleep(30);
}
return 0;
}

DWORD WINAPI Thread2(LPVOID lpParam1)

{
for (int j=0;j<100;j++)
{
WaitForSingleObject(sp1,INFINITE);
cout<<"Potok "<<2<<endl;
ReleaseSemaphore(sp1,1,NULL);
Sleep(5);
}
return 0;
}

VOID main()
{
sp1=CreateSemaphore(NULL,1,1,NULL);

h1 = CreateThread(NULL,0,Thread1,NULL,0,NULL);
h2 = CreateThread(NULL,0,Thread1,NULL,0,NULL);

int uo;
cin>>uo;
}
Здесь два потока выводят свои номера. Учитывая, что у 2-го задержка меньше, то примерно через каждые пять выводов 2-го должен выводить 1-ый. Но выводит только первый.
Написал тоже самое в Delphi, всё работает, единственное как я уже говорил, я там потоки создаую по другому, но для синхронизации всё тоже самое использую.
Ни как не могу понять как тут это работает.

Добавлено: Всё нашел ошибку, h2 = CreateThread(NULL,0,Thread1,NULL,0,NULL);. Там Thread2 должен быть.
 

lazybiz

Well-Known Member
03.11.2010
1 339
0
#4
Вопрос исчерпан?

Добавлено: Твой последний код можно даже упростить, заодно это будет пример как можно передать простейщий параметр потоку.
C++:
#include "stdafx.h"
#include <iostream>
#include "windows.h"
using namespace std;

HANDLE h1,h2;
HANDLE sp1;

DWORD WINAPI a_thread( LPVOID lpParam )
{
int  i_thread = (int)lpParam;
for (int i=0;i<100;i++)
{
WaitForSingleObject( sp1, INFINITE );
cout<<"Potok "<< i_thread <<endl;
ReleaseSemaphore( sp1, 1, NULL );
Sleep( i_thread == 1 ? 30 : 5 );
}
return 0;
}

VOID main()
{
sem = CreateSemaphore( NULL, 1, 1, NULL );
h1 = CreateThread( NULL, 0, a_thread, (LPVOID)1, 0, NULL );
h2 = CreateThread( NULL, 0, a_thread, (LPVOID)2, 0, NULL );
}