Click to See Complete Forum and Search --> : MultiThread call a VB COM do not improve performance


dwu
July 11th, 2005, 10:30 AM
I created a c++ multithread ATL DLL, and each thread will call a component written with VB6 to do a stored procedure call. I found there is no different in performance between a single thread and multithread. Help!


Trace time in thread like this:
1 Thread
vb function call time: 109
c++ other code time: 62

2 thread
vb function call time: 156
c++ other code time: 62

3 thread
vb function call time: 256
c++ other code time: 62


and VB component log time:
1 Thread
vb function call time: 109
c++ code time: 62

2 thread
vb function call time: 109
C++ code time: 110

3 thread
vb function time: 109
c++ code time: 219


C++ code like this:
unsigned _stdcall CMTTest::DoVBFunction(LPVOID pThis)
{


CMTWrapper* pThisObject = static_cast<CMTTest*>(pThis);

HRESULT hr=S_OK;
DWORD dwLastStart = GetTickCount();
DWORD dwCount;// = GetTickCount();

CComPtr<_DMTTest> pServer;

hr=pServer.CoCreateInstance (pThisObject->mszServerProgID);

for (;;) {


if (WAIT_OBJECT_0 == WaitForSingleObject(pThisObject->mhParamMutex ,50)){
bDoJob = !(pThisObject->mParamQueue.empty());
dwMyId = ::GetCurrentThreadId();
pMap = pThisObject->mThreadsWorking.find(dwMyId);
if (pMap == pThisObject->mThreadsWorking.end()) {
ReleaseMutex(pThisObject->mhParamMutex);
pThisObject->Fire_ServerFuncDone(FATAL_SERVER_ERROR);
return -1;
}
pMap->second = bDoJob;

ReleaseMutex(pThisObject->mhParamMutex);
}
else
bDoJob = FALSE;

if (bDoJob) {

dwCount=GetTickCount() - dwLastStart;
dwLastStart=GetTickCount();
AtlTrace(_T("Thread: %d, C++ code Time: %d.\n"),dwMyId, dwCount);

hr = pServer->raw_ServerFunc (dwMyId,&nReturn,&pvParam);

dwCount=GetTickCount() - dwLastStart;
dwLastStart=GetTickCount();
AtlTrace(_T("Thread: %d, VB function call Time: %d.\n"),dwMyId, dwCount);
}

if (WAIT_OBJECT_0 == WaitForSingleObject(pThisObject->mhTimeToDie,50))
{
return 0;
}

}

return 0;
}



Thanks.
David

wildfrog
July 11th, 2005, 07:34 PM
Without code-tags it's difficult to read and comment on your code, but maybe you problem has to do with threading models. Maybe your VB component is a "single threaded" component and only allows one call at a time?

- petter

Arjay
July 12th, 2005, 01:22 PM
If the COM object is an STA object, you are going to kill performance with the WaitForSingleObject call. This is because an STA objec requires a message pump to process the COM calls. By using WaitForSingleObject you are blocking these calls. You should see performance improvement by switching to a MTA COM object (which doesn't use a message pump) or by using the STA object with a MsgWaitForMultipleObjects (and process msg during the wait).

Arjay

dwu
July 13th, 2005, 10:46 AM
I have included all the source codes in the attached MyTest.zip

There are three projects:
VBTestCOM project is a apartment threaded DLL, it has one function doing a stored procedure call. This DLL will be called from C++ multithread.

C++ test project is a ATL multithreaded DLL, it just simple created multithread, and call VBTestCom's doSPCall function in each thread.

VB client:
It set thread number and start a loop calling C++ DLL's Do function.

You need created a stored procedure in SQL Server NorthWind database like this:
create PROCEDURE dbo.usp_Test
AS
BEGIN
insert Categories(CategoryName,[Description])
values( 'CatName', convert(varchar(30),getdate(),9))

WAITFOR delay '00:00:00.100'
end
It create a record in Categories and delay 100 milliseconds.

In C++ debug, Change the thread number and you will see no performance improvement.

It's frustrating! Help!

Arjay
July 13th, 2005, 12:43 PM
Two things:
1) Read my previous post as to why you may not see a speed improvement with an STA COM object (apartment threaded object like your VB dll) in a multithreaded environment.
2) WAITFOR delay '00:00:00.100' What's this for? Won't this lock the table and prevent other inserts?

Arjay

dwu
July 13th, 2005, 04:33 PM
1) I change to MsgWaitForMultipleObjects and still the same: No performance improvement.

2) In SP WAITFOR delay '00:00:00.100' just simply delay SP call for 100 milliseconds before SP call return. It's easy to see how long I spent in VB function.

David

Arjay
July 13th, 2005, 05:18 PM
1) I change to MsgWaitForMultipleObjects and still the same: No performance improvement.I may have mislead you regarding MsgWaitForMultipleObjects. In an STA com object, each com request gets serialized. AFAIK, a hidden window gets created for the process that processes STA com requests. The window uses a message pump that serializes the requests. This occurs because, by marking the COM object as STA, you are informing the COM system that this object is not thread safe, and COM tries to help achieve thread safety by serializing the requests via the message pump. What this means is that, although you are instantiating multiple com objects on separate threads, all the requests get funnelled into the same message pump. In other words, if you have two threads and each create the same STA object, even if the threads can run concurently (like on a multiproc machine), the individual calls to the com objects are only going to occur one at a time because of the message pump. Understand?

The answer here is to make the com object a free threaded object (which precludes you from doing this in VB, AFAIK)

2) In SP WAITFOR delay '00:00:00.100' just simply delay SP call for 100 milliseconds before SP call return. It's easy to see how long I spent in VB function.Okay forget about the STA/MTA side of things. Let's look at this from strickly a db point of view. I question the use of the delay here because I'm not sure at what point the table lock gets released in the stored procedure. Does it occur immediately after the Update command (before the delay) or does it occur after the delay command (i.e., after the stored procedure goes out of scope)? If the table doesn't unlock until after the delay command, you are creating a bottle neck because any subsequent stored procedure calls won't be able to lock the table for the insert until after the first call has unlocked. See the bottleneck?

Arjay

dwu
July 14th, 2005, 12:03 PM
I guest I already solve the problem with the help Willy Denoyette and Carl Daniel: I need to initialize a apartment in each thread to call a VB COM object.

http://msdn.microsoft.com/newsgroups/default.aspx?query=No performance improvement for MultiThreaded call to a VB COM&dg=microsoft.public.dotnet.languages.vc

Thanks, Guys
David