 |
|
 |
Hi,
Thanks a lot for your usefull article. Unfortunately your old article on "worker thread pooling" is not available. It would be very kind if you could provide me with the article and specifically its sample project.
Regards
|
|
|
|
 |
|
 |
clear and simple, work very good
|
|
|
|
 |
|
 |
hi
NOT USING MFC
iam downloading xml file from the server using HTTP CONNECTION
i want to update the progress bar to show the status of the downloading
i.e how much the file is downloaded
Iam using win32application with typical hello world application
i added the progress bar to main menu by using createwindow()
the problem is
i searching for the solution how to update the progress bar
while file is downloading....
1)how to get get sizeof the file downloaded
2)how to use interval to get size
waiting for suggestion from the Gurus
sample code will help me more
K.C.S
|
|
|
|
 |
|
 |
I know that m_cs is CCriticalSection.When Synchronizing resource,I can do m_cs.Lock or m_cs.Unlock.In yourvoid CMThreadedJobQ::addJob(CJob *pJob),may I can change CSingleLock sLock(&this->m_cs);
sLock.Lock(); intom_cs.Lock(); ? In other words,I may not
use the class CSingleLock?
|
|
|
|
 |
|
 |
I find it simpler to use this kind of construct :
{ // begin scope of lock
CSingleLock lock( &m_cs, true );
... // locked code here
} // end scope of lock
The critical section will be unlocked automatically when the lock object falls out of scope and is destroyed.
|
|
|
|
 |
|
 |
Just for test, I used the files provided by the author and replaced the following code
void CJobType1::execute()
{
CPrgUIThread* pTh =(CPrgUIThread*) AfxBeginThread(RUNTIME_CLASS(CPrgUIThread));
pTh->m_ExecuterID = this->getID();
Sleep(200);//This is required for initializing the Dialog
CPrgDlg *pDlg = (CPrgDlg *)pTh->m_pMainWnd;
pTh->m_pMainWnd->SetWindowText("Job Type 1 is running");
pDlg->m_prgBar.SetRange(0,100);
//Post message here to update the message..
while(pDlg->m_prgBar.GetPos() <100)
{
pDlg->m_prgBar.SetPos(pDlg->m_prgBar.GetPos()+1);
Sleep(150);
}
pDlg->PostMessage(WM_CLOSE);
}
By this one :
void CJobType1::execute()
{
Sleep(5000);
CStdioFile stdFile;
CTime t = CTime::GetCurrentTime();
CString csFileName = t.Format( "%A_%B_%d_%Y_%M_%S.txt" );
if( !stdFile.Open( csFileName, CFile::modeCreate
| CFile::modeWrite | CFile::typeText ) ) {
#ifdef _DEBUG
afxDump << "Unable to open file" << "\n";
#endif
exit( 1 );
}
stdFile.WriteString("My Test");
stdFile.Close();
}
But, when I execute the app and I request 10 job1, why there are less than 10 files created...
OK, perhaps I don't understand something, but can someone help me ???
-- modified at 5:46 Thursday 15th September, 2005
|
|
|
|
 |
|
 |
hello speleo74:
Because following codes:
CTime t = CTime::GetCurrentTime();
CString csFileName = t.Format( "%A_%B_%d_%Y_%M_%S.txt" );
may get same result(File Name) between certain jobs as they are processed "synchronously",which will decrease file numbers, u can make some changes. the following codes i've tested will work:
void CJobType1::execute()
{
CStdioFile stdFile;
CTime t = CTime::GetCurrentTime();
static int cnt = 0; CString csTime = t.Format( "%A_%B_%d_%Y_%M_%S.txt" );
CString csFileName;
csFileName.Format("%d%s", cnt++, (LPSTR)(LPCTSTR)csTime);
if( !stdFile.Open( csFileName, CFile::modeCreate
| CFile::modeWrite | CFile::typeText ) ) {
#ifdef _DEBUG
AfxMessageBox("Unable to open file");
#endif
exit( 1 );
}
stdFile.WriteString("My Test");
stdFile.Close();
return;
}
|
|
|
|
 |
|
 |
I use this call in a FIFO mode and i found a crash when the thread was complete
For one thread fifo mode queue here is the fixe
// change > to >=
if(pExecuter->m_pJobQ->getNoOfExecuter() >= pExecuter->m_pJobQ->getMaxNoOfExecuter())
{
pExecuter->stop();
singleLock.Unlock();
// be sure to suspend this thread
pExecuter->m_pExecuterThread->SuspendThread();
}
Programming is not an end in itself but only a means to an end
|
|
|
|
 |
|
 |
Quite impressive. I have some suggestions. I would think using Events instead of the code like this would be much more efficient. Try looking up CEvent in MFC or create your own wrapper class using the Event handle.
//wait till the job gets completed
while( pJob.m_Completed != TRUE)
{
sleep(100);
}
//Now we can delete the job instance as the job got completed
delete pJob;
|
|
|
|
 |
|
 |
Another suggesstion I have is to make this platform independent. Possiblly using Thread handle for windows, pthreads for unix etc. And use pre-processors to detect this at run time. Would be even more impressive.
|
|
|
|
 |
|
 |
In demo project, you shouldn't call refresh from destructor, in race condition it might never return and cause dead lock in critical section.
They should be just plain empty function.
CJobType1::~CJobType1()
{
}
CJobType2::~CJobType2()
{
}
Don't know much < I, don't care much > I, while I am here ... just be ME
|
|
|
|
 |
|
 |
Hi,
It is Nice application. I need ur Help in My Apps.It is Client Server Based Application. My Client Application should be connect to different Servers parallel.So that I am planning to implement Multithreading and Sockets.Pl help me How to write? if any piece code.
Adavanced thanks
satya
|
|
|
|
 |
|
 |
Have u done it ...?
I did the same ...simply do the follwing ...
if u want to use both Socket server and multithreaded Q then it seems u want to process the received messages thro the Q rgt ? Ok if so ...( i am presumptous guy ) ..do this way
in the OnReceive() or FD_READ Call back of your socket server
{
CJobType1 *pJob;
pJob= new CJob();
// now as u want the incoming buffer to be handled in CJobType1 ...set the buffer tothe CJobType1 as below ..
pJob->SetBuffer(buffer) ...
and in the Execute () handle the message and there u go ...
pApp->m_jobQ.addJob(pJob);
}
now if u include MultiThreadedJobQ ...header cpp and JobExecuter .h and cpp as mentioned by auther all thins will be done cool ..
regds
Dharani Babu S
I beleive in murphy's law
|
|
|
|
 |
|
 |
Hi auther
I am very excited at the way you have written this code . have seen a lot of thread pool codes but none hav ebeen as reusable as urs . I am using the job q for my multithreaded socket server purpose. its proving very good and exactly what i wanted . pls keep it up by posting more codes to the forum ...
regds
dharani babu s
|
|
|
|
 |
|
 |
These classes have a race condition in which a worker thread will occassionally be suspended forever while it's holding a valid job. As a consequence, the job is never executed.
The reason for the race condition is the use of SuspendThread and ResumeThread. As background, SuspendThread and ResumeThread affect the "suspend count" of a thread, and the Windows scheduler will not execute a thread unless its suspend count is zero. SuspendThread increments the suspend count while ResumeThread decrements it. Importantly, however, ResumeThread will never decrement the suspend count below zero, which is one source of the race condition.
The other source is the way SuspendThread and ResumeThread are used. At some point, the main JobObserver thread (in CMThreadedJobQ) is suspended and the worker (CJobExecuter) thread is just completing its job. At that point, the worker puts itself on a list of free workers, resumes the JobObserver thread, and suspends itself. The JobObserver wakes up, gives the worker a new job, resumes the worker, and then suspends itself. And so on.
And there's the source of the race condition. It's possible (likely) that the worker thread will lose its time slice between the time it has resumed the main JobObserver therad and the time it suspends itself. The JobObserver thread gives the worker a new job and resumes it, but because the worker is still running, its suspend count is already zero and can't go any lower. Eventually the worker will get a new time slice and will pick up where it left off, by calling SuspendThread on itself, at which point the suspend count is incremented to "1" where it will stay forever.
This explains why (in my question below) the number of executing threads never seems to be high enough even given the abundant presence of waiting jobs. Apparently, jobs were being delegated to threads that became suspended indefinitely, and were never performed.
It also explains memory leaks found when the program exits. The leaks correspond to unexecuted jobs being held by suspended/frozen threads.
I tried the following solution but it didn't work. Apparently, a critical section gets locked in a way that I don't follow, and prevents scheduling of anything other than the first job. My idea was to let the JobObserver check the return value from ResumeThread to ensure that it indicates that the worker has been suspended. If not, relinquish the JobObserver's time slice to give the worker a chance to suspend itself first.
// replace the following code ....
void CJobExecuter::execute(CJob* pJob)
{
this->m_pJob2Do = pJob;
//Now the thread should be resumed to process the Job
::Sleep(0);
this->m_pExecuterThread->ResumeThread();
}
// with the following ...
void CJobExecuter::execute(CJob* pJob)
{
this->m_pJob2Do = pJob;
//Now the thread should be resumed to process the Job
// ::Sleep(0); // not needed
while ( 1 != m_pExecuterThread->ResumeThread() )
{
::Sleep( 0 );
}
}
But as I said, it didn't work.
I suspect (but haven't investigated) that there's a similar "mirror image" race condition where the main JobObserver thread can become suspended indefinitely too. In that case, the whole system would grind to a halt.
This set of classes represents a fine idea, but I think they should be re-written using "events" (use CreateEvent()) intead of depending on SuspendThread and ResumeThread.
|
|
|
|
 |
|
|
 |
|
 |
I think in race condition the multithreads causes CJobExecuter::ThreadFunction and Main Dlg Window Refresh function call of CMThreadedJobQ.m_cs (critical section) to be trapped in Dead Lock when time slice leap. Just take a look at the code, in race condition when UI Thread exit, it try to refresh and in numbers it will surely crash with the while loop in ThreadFunction.
Resume and suspend seems not to be the problem.
Don't know much < I, don't care much > I, while I am here ... just be ME
|
|
|
|
 |
|
 |
I tried to create 20 threads (actually, 20 CJobExecuter's), but found out that you hard-coded a limit of 11:
void CMThreadedJobQ::setMaxNoOfExecuter(int value)
{
this->m_cs.Lock();
if(value >1 && value <11) // <--- hard-coded limit of 11
this->m_MaxNoOfExecuter = value;
m_pObserverThread->ResumeThread();
this->m_cs.Unlock();
}
I edited the upper limit to a higher number, but found that even though m_MaxNoOfExecuter is correctly set to my desired value of 20, 20 threads are never created (although it seems like more than 11 were created).
Is there a reason why these classes will not create a larger number of threads? Or a reason why you hard-coded the limit of eleven?
Regards,
Mike
PS: I think it would be better if setMaxNoOfExecuter returned a value indicating successful completion of the function, particularly if there's a reason behind limiting the number of threads. For example, it could return the new value of m_MaxNoOfExecuter. It also would be better to set m_MaxNoOfExecuter to a boundary of the range, rather than ignore the request entirely. For example:
int CMThreadedJobQ::setMaxNoOfExecuter(int value)
{
if ( value is inside of range )
{
this->m_MaxNoOfExecuter = value;
}
else
{
this->m_MaxNoOfExecuter = max or min of range, as appropriate
}
return m_MaxNoOfExecuter;
}
with all the needed Lock's and Unlock's, of course.
|
|
|
|
 |
|
 |
Hi author
This is a nice article . But I am wondering if u cld wirte an article to deal with multithreaded sockets The reason being I am gonna work on that - so an article from u will add values to it .
regards
dharani
|
|
|
|
 |
|
 |
it's a good class, but i worked to integrate this class into my activex control, i didn't manage to build the project , cause it could not register the control with the added multithread functionnality.
What can i do?
i need help?
i wonder if it is possible to use this class with activex controls, if yes, would you please give me idea how to add it in my activex source code.
Regards.
Thanks.
|
|
|
|
 |
|
 |
When the Multithreaded Jobs is not finish,but exit the application, then you will detect memory leaks! -- This is the problem!
|
|
|
|
 |
|
 |
Modify files as follow:
JobExecuter.cpp
CJobExecuter::~CJobExecuter()
{
//The lines below are added later to solve the memory leak.
//The leaks are found and solved by "Guitool" having member no Member No. 7253
if(this->m_pExecuterThread!= NULL )
{
//this->m_pExecuterThread->m_pMainWnd->PostMessage(WM_CLOSE);
if(m_pJob2Do != NULL)
{
delete m_pJob2Do;
m_pJob2Do = NULL;
} this->m_pExecuterThread->ExitInstance();
delete m_pExecuterThread;
}
//End of code suggested by "Guitool".
}
JobType1.cpp and JobType2.cpp
CJobType1::~CJobType1()
{
CJobQApp *pApp =(CJobQApp *) AfxGetApp();
if(::IsWindow(pApp->m_pMainWnd->GetSafeHwnd()))
((CJobQDlg *) pApp->m_pMainWnd)->Refresh();
if(m_pTh)
{
m_pTh->ExitInstance();
m_pTh->Delete();
}}
xifan from China
|
|
|
|
 |
|
 |
Run the example,add several jobs(6 jobs),increase No.of Thread to process Jobs(up to 4),then decrease Thread to process Jobs(down to 2 or 3),after first 4 jobs completed the error shown.
Is there an bug?
|
|
|
|
 |
|
 |
One thing I am thinking about is to implement an event when the one job is finished so that the main thread get the feedback. Anyone can help advise something on that ?
|
|
|
|
 |
|
 |
Step 1) I run your program -- Threads== 2 ...ok
step 2) I add two jobs (from Add job type 1) threads == 4..ok
step 3) both the progrss bar are completed.
step 4) now i see task manager it show me 3 threads runnig why?
for 10 jobs(I SELECT THREADS ALSO 10) --(task manager shows threads == 22)
progress bar==OVER
now task manager shows thread==12...why?
now i reduce no of jobs to 2 (threads also to 2)
and i run 1 job
task manager shows threads == 13
progrss bar over threads ==12....why
and then it say "DEBUG ASSERTION FAIL"
I only want to know why the task manager shows me extra number of threads,
after all the progress bar has completed their task...i think it should be
Thread==2?
|
|
|
|
 |