15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Multithreading problem...

Syed -- sxs296@psu.edu
Sunday, February 16, 1997

Environment : Visual C++ 4.2-flat, Windows 95, Windows NT 4.0

Hi there,

My application sometimes will delete, move directories/files on request from
user. And I perform the task using IContextMenu::InvokeCommand methods.
Actually it behaves very much like Windows Explorer (CTreeCtrl at the left
pane, CListView at the right pane). Upon successfully filling out the
CListView, I launch a separate thread (notification thread) so that it will
wake up if there is any harddisk change in that particular directories (the
one being displayed in CListCtrl). So, whenever there is a change in that
particular directory, that thread will inform the CListCtrl and do whatever
necessary to update the right pane. The real problem is whenever the user
want to delete say.. 20 files.. the notification thread will wake up many
times and therefore, inform the CListCtrl many times. This in turn, will
update the right pane many times. So, I'm left thinking what should I do so
that the right pane will be updated ONLY after all the hard disk operation
has ended. I have come up with a quite good solution I guess: 
Use WaitForSingleObject (after a harddisk-write is detected, then use
FindNextChangeNotification) to wait for the change of harddisk again. If
there's no hard disk activity within 1 second (WaitForSingleObject expires
within 1 second), then it's assumed that the copying/removing thread has
terminated. This technique really improves the performance, but I'm still
thinking whether there's other method which can detect the completion of
hard-disk write. Or is there a better method than mine that anyone (could
think/have written) of?
The full code for the notification thread is as follows :-

// The thread will wake up if either/both of two occurs:-
// 1 - the program itself sends a signal (g_event - instantiated from CEvent)
       which in this case, will update the pThreadParam->hChange...
// 2 - change of harddisk structure - harddisk write.

UINT ThreadFunc(LPVOID pParam)
{
        THREAD_PARAM *pThreadParam = (THREAD_PARAM*)pParam;
	HANDLE Threads[2] = { pThreadParam->hChange, g_event };
	DWORD dwResult;
#ifdef _DEBUG
	int temp;
#endif

	pThreadParam->hChange = ::FindFirstChangeNotification(
			pThreadParam->szDirectory, FALSE,
			FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME);
	if (pThreadParam->hChange == INVALID_HANDLE_VALUE)
	{
		TRACE("Error in notification for directory %s\n",
			pThreadParam->szDirectory);
		return (UINT)-1;
	}

	TRACE("Starting with %s\n", pThreadParam->szDirectory);
	while (TRUE)
	{
		Threads[0] = pThreadParam->hChange;
		dwResult = ::WaitForMultipleObjects(2, Threads, FALSE, INFINITE);
		ASSERT (dwResult != WAIT_FAILED);
		if (dwResult == WAIT_OBJECT_0) // First handle notifies...
		{
			// Test repitition...
			do
			{
				                        ::FindNextChangeNotification(pThreadParam->hChange);
			}while (::WaitForSingleObject(pThreadParam->hChange, 500) != WAIT_TIMEOUT);
			::PostMessage(pThreadParam->hWnd, WM_USER_CHANGEHD, 0,
(LPARAM)pThreadParam->szDirectory);
			//::FindNextChangeNotification(pThreadParam->hChange);
		}
		else if (dwResult == WAIT_OBJECT_0+1)
		{
			// Start a new notification...
			g_event.ResetEvent();
			TRACE("New notification with %s\nb", pThreadParam->szDirectory);
			pThreadParam->hChange = ::FindFirstChangeNotification(
				pThreadParam->szDirectory, 
				FALSE,
				FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME);
		}
	}
	return 0;
}




Leo PL -- wul@PO5.pl.unisys.com
Tuesday, February 18, 1997


Access Jet database is not thread-safe. But if  I have to do some multi-
theading on Access database (not Access 97 but older versions), Can I use
ODBC?

Any suggestion on things I should look out will be appreciated.





Kenneth A. Argo -- argo@rias.COM
Wednesday, February 19, 1997

The issue is not as much as ODBC as it is with the driver below.  ODBC =
or not the Jet Engine, which you may have to use with ODBC is not thread =
safe so you won't have any luck.  What I ended up doing allows almost =
mutitasking through the Jet engine, but not quite.  I create a named =
mutex, each thread accessing the DB creates one of the same name.  Then =
just before any DB call the thread gets ownership of the mutex then =
executes the DB call.  This way you can have multiple threads accessing =
the DB, but the mutex will insure that only 1 is inside the DB engine at =
a time.

Ken



----------
From:  Wu, Leo                     PL[SMTP:wul@PO5.pl.unisys.com]
Sent:  Tuesday, February 18, 1997 10:21 AM
To:  'mfcl'
Subject:  RE: Multithreading problem...


Access Jet database is not thread-safe. But if  I have to do some multi-
theading on Access database (not Access 97 but older versions), Can I =
use
ODBC?

Any suggestion on things I should look out will be appreciated.






Richard Morris -- richard@softwaremachine.com
Wednesday, February 19, 1997

[Mini-digest: 2 responses]

At 03:21 PM 2/18/97 GMT, you wrote:
>
>Access Jet database is not thread-safe. But if  I have to do some multi-
>theading on Access database (not Access 97 but older versions), Can I use
>ODBC?
>
>Any suggestion on things I should look out will be appreciated.


Here is a reply which was posted a while back which might be of some
assistance to
you.

Hope this helps.
************************************************
Subject: Re: DAO/CDao classes in background threads ? (fwd)
Date: Mon, 03 Feb 1997 13:15:09 -0800

----Forwarded----
G'day George,

George Neuner wrote:
> =

> On 29 Jan 1997 21:49:43 GMT, "Greg Turner" 
> wrote:
> =

> >Dao cannot be used from multiple threads.
> >
> >Here is an excerpt from the online documentation:
> >
> >DAO in DLLs, Multithreaded Applications, and OLE Controls
> >This topic discusses the MFC DAO classes with respect to support for usi=
ng
> >the MFC DAO classes:
> >=B7      In dynamic link libraries (DLLs)
> >=B7      In OLE controls
> >=B7      In multithreaded applications
> >=B7      In console applications
> >=B7      In applications built for Unicode or double-byte character syst=
ems (DBCS)
> >
> >You can use the MFC DAO classes in any DLL. This means you can also use =
the
> >classes in OLE controls.
> >DAO itself is not multithreaded, so you can=92t use the MFC DAO classes =
in
> >multiple threads. Confine your DAO code to a single thread of execution.=

> >
> =

> Yeah, but ...
> =

> All the objects and code ARE in a single thread - it just isn't the
> main application thread.
> =

> George Neuner
> gneuner@dyn.com

I managed to get the DAO to work in another thread last year - so forgive m=
e if things have changed =

so that what I did is no longer the method de jour.

Basically, what the documentation said is true - all DAO calls must be made=
 from a single thread.  I =

used the main thread as the GUI thread, and a 'background' thread to do the=
 database work.  =

Communication between the two was via messages and essentially a shared obj=
ect, gated by locks.

I found I had to do the following:

1. Initialise OLE as follows in the CWinThread derived object (your backgro=
und DB thread):

        // initialise OLE
        OleInitialize(NULL);

2. Instantiate the CDaoDatabase object in the DAO thread.

You *cannot* aggregate it in the CWinThread derived object as it would be i=
nstantiated before the =

OleInitialize() call (see previous point).  It also seemed to cause problem=
s when trying to exit the =

thread (and it went through its destructor).

3. Open the database as per usual.

4. Instantiate a CDaoRecordset object for each table you wish to open.  Aft=
er creating the object, =

open the record set.

5. On termination, reverse the above process, including a call to OleUninit=
ialize():

        // uninitialise OLE
        OleUninitialize();

6. Finally, there is (was?) a bug in the DAO that expected the DAO stuff to=
 be opened from the main =

thread.  This caused problems when you terminated the app, since the DAO wa=
s being used from two =

threads.

Therefore, in your ExitInstance() method in the DB (background) thread, put=
 in the following:

        // ** BUG ** The DAO must be terminated from the thread that 
initialised i=
t
        // if the DAO is initialised, make sure we terminate it from this 
thread
        if (pApp->m_lpfnDaoTerm)
                pApp->m_lpfnDaoTerm();

Note that you have to get the pointer to the CWinApp object.

Hope this works.

Cheers,
Graham
-- =

Graham Freckleton
nnyxfc@ny.ubs.com


****************************************************************
Live now.
Make now always the most precious time.
Now will never come again.
	 - Captain Jean-Luc Picard, U.S.S. Enterprise

-----From: "Wu, Leo                     PL" 


Thank you for your response.

I assume you created both DAO DB object and CMutex lock at the
prime  thread. Am I right?

 ----------
|From: Kenneth A. Argo
|To: Wu, Leo                     PL; 'mfcl'
|Subject: RE: Multithreading problem...
|Date: Wednesday, February 19, 1997 1:20PM
|
|
|The issue is not as much as ODBC as it is with the driver below.  ODBC or
|not the Jet Engine, which you may have to use with ODBC is not thread safe
|so you won't have any luck.  What I ended up doing allows almost
|mutitasking through the Jet engine, but not quite.  I create a named mutex,
|each thread accessing the DB creates one of the same name.  Then just
|before any DB call the thread gets ownership of the mutex then executes the
|DB call.  This way you can have multiple threads accessing the DB, but the
|mutex will insure that only 1 is inside the DB engine at a time.
|
|Ken
|
|
|
| ----------
|From:  Wu, Leo                     PL[SMTP:wul@PO5.pl.unisys.com]
|Sent:  Tuesday, February 18, 1997 10:21 AM
|To:  'mfcl'
|Subject:  RE: Multithreading problem...
|
|
|Access Jet database is not thread-safe. But if  I have to do some multi-
|theading on Access database (not Access 97 but older versions), Can I use
|ODBC?
|
|Any suggestion on things I should look out will be appreciated.
|
|
|



Blane Nelson -- blanen@coresoft.com
Thursday, February 20, 1997

Leo,

Just finished up some code that does this.  The only problem is that you =
have to Open and Close the database on each thread.  You can't open the =
database on one thread and access it on another.  As near as I've been =
able to find out, this is a limitation of the Access ODBC driver.  =
According to the ODBC docs, ODBC is thread-safe but it's still up to the =
driver to be thread-safe as well and different drivers may handle a =
multi-threaded environment differently.  I have only worked with Access =
and FoxPro and they both work the same way, you may see different =
behaviors from different drivers.

-Blane Nelson
-Coresoft Technologies



----------
From: 	Wu, Leo                     PL[SMTP:wul@PO5.pl.unisys.com]
Sent: 	Tuesday, February 18, 1997 8:21 AM
To: 	'mfcl'
Subject: 	RE: Multithreading problem...


Access Jet database is not thread-safe. But if  I have to do some multi-
theading on Access database (not Access 97 but older versions), Can I =
use
ODBC?

Any suggestion on things I should look out will be appreciated.








mwelch@tsbbank.co.uk
Saturday, February 22, 1997

Environment: MSVC4.2-flat/Win95, MSVC2.2/NT3.51

Leo,

FWIW I create and Open a CRecordSet in the main UI thread, pass a pointer t=
o=20
the CRecordSet (as part of a structure) to a worker thread. When the worker=
=20
thread is complete it notifies the main thread which in turn closes the=20
CRecordSet.

This works without problems using

MSVC 4.2 under Win95 Access2 MDB and Access95 driver.
MSVC 2.2 under NT 3.51 Access2 MDB and Access2 driver.

Blane's point about opening on one thread and closing on another is valid.

Hope that helps.

Martin
 ----------
From: blanen@coresoft.com
To: mfc-l@netcom.com; Martin Welch
Subject: RE: Multithreading problem...
Date: 21 February 1997 19:05

Received: from majordomo.netcom.com (206.217.29.105) by mail.tsbbank.co.uk
(Integralis SMTPRS 1.4) with SMTP id ; Fri,
21 Feb 1997 19:03:54 +0000
Received: by majordomo.netcom.com (8.7.5/8.7.3/(NETCOM MLS v1.01)) id
VAA09000; Thu, 20 Feb 1997 21:30:33 -0800 (PST)
Message-Id: <01BC1F23.75D5E600@blanen.coresoft.com>
From: Blane Nelson 
To: "'mfc-l@netcom.com'" 
Subject: RE: Multithreading problem...
Date: Thu, 20 Feb 1997 11:44:36 -0700
MIME-Version: 1.0
Sender: owner-mfc-l@majordomo.netcom.com
Errors-To: owner-mfc-l@majordomo.netcom.com
Precedence: bulk
Reply-To: mfc-l@netcom.com
Content-Type: text/plain; charset=3D"us-ascii"




Become an MFC-L member | Вернуться в корень Архива |