sinister
asked on
Problems with CDaoDatabase and multiple threads
Hello,
I am writing a program that handles database operations for a IVR telephone system. I have numerous threads running that handle the db operations. The problem is that when many calls hangup at the same time my program has to log information to an Access database the threads crash on the open database call. I use a global critical section object around the code and I open the database in exclusive non-shared mode but still there are crashes. Note, that this works for a few hours under heavy stress but eventually crashes.
My question is that, has anyone encountered such problems with MFC Dao classes. Also, does AfxDaoInit and AfxDaoTerm have to always be called before and after any database operations? These functions seem to create their own threads and I have a feeling that they are screwing up. The crash seems to happen inside the Dao350.dll because when I click on the "Cancel" button on the famous Access Violation window MSStudio opens up with Dao350.dll dissambeley.
Please, let me know if this question is understandable. Any help would be appreciated. Thanks.
I am writing a program that handles database operations for a IVR telephone system. I have numerous threads running that handle the db operations. The problem is that when many calls hangup at the same time my program has to log information to an Access database the threads crash on the open database call. I use a global critical section object around the code and I open the database in exclusive non-shared mode but still there are crashes. Note, that this works for a few hours under heavy stress but eventually crashes.
My question is that, has anyone encountered such problems with MFC Dao classes. Also, does AfxDaoInit and AfxDaoTerm have to always be called before and after any database operations? These functions seem to create their own threads and I have a feeling that they are screwing up. The crash seems to happen inside the Dao350.dll because when I click on the "Cancel" button on the famous Access Violation window MSStudio opens up with Dao350.dll dissambeley.
Please, let me know if this question is understandable. Any help would be appreciated. Thanks.
Database always has one or other problems when used in threads
Call AfxDaoInit() in EACH thread you created and AfxDaoTerm() only once in your application clean-up code.
Also you need to call AfxDaoInit() if you use callback functions.
Hope this helps
Also you need to call AfxDaoInit() if you use callback functions.
Hope this helps
ASKER
Currently I am opening, running query, and then closing the database, do I have to call AfxDaoInit before I do the database open?
If you do it in your main application thread then NO
If you do it in separate thread or callback functions you need to call AfxDaoInit() BEFORE any call to DAO functions in the current thread.
If you do it in separate thread or callback functions you need to call AfxDaoInit() BEFORE any call to DAO functions in the current thread.
If you want to access the Jet database from a multithreaded app, then I'll suggest that you switch to OLEDB instead.
OLEDB has full support for multithreaded access to the database.
Take a look at the classes CDataSource, CSession, CRowset.
Here is an example of opening a jet database using OLEDB:
HRESULT TestFunction()
{
CDataSource ds;
CSession session;
wchar_t* pwcPath = "C:\\MyData.mdb";
CDBPropSet dbinit(DBPROPSET_DBINIT);
dbinit.AddProperty(DBPROP_ INIT_DATAS OURCE, pwcPath);
dbinit.AddProperty(DBPROP_ INIT_MODE, (long)(DB_MODE_READWRITE)) ;
dbinit.AddProperty(DBPROP_ INIT_PROMP T, (short)DBPROMPT_NOPROMPT);
dbinit.AddProperty(DBPROP_ INIT_LCID, (long)GetSystemDefaultLCID ());
dbinit.AddProperty(DBPROP_ AUTH_USERI D, OLESTR("Admin"));
dbinit.AddProperty(DBPROP_ AUTH_PASSW ORD, OLESTR(""));
#if(USE_JET_VERSION==40)
hr = ds.Open(CLSID_JETOLEDB_4_0 0, &dbinit);
#else
hr = ds.Open(CLSID_JETOLEDB_3_5 1, &dbinit);
#endif
if(FAILED(hr))
return hr;
hr = session.Open(ds);
if(FAILED(hr))
return hr;
//
// ... Do something with it ...
// ....
session.Close();
ds.Close();
return S_OK;
}
OLEDB has full support for multithreaded access to the database.
Take a look at the classes CDataSource, CSession, CRowset.
Here is an example of opening a jet database using OLEDB:
HRESULT TestFunction()
{
CDataSource ds;
CSession session;
wchar_t* pwcPath = "C:\\MyData.mdb";
CDBPropSet dbinit(DBPROPSET_DBINIT);
dbinit.AddProperty(DBPROP_
dbinit.AddProperty(DBPROP_
dbinit.AddProperty(DBPROP_
dbinit.AddProperty(DBPROP_
dbinit.AddProperty(DBPROP_
dbinit.AddProperty(DBPROP_
#if(USE_JET_VERSION==40)
hr = ds.Open(CLSID_JETOLEDB_4_0
#else
hr = ds.Open(CLSID_JETOLEDB_3_5
#endif
if(FAILED(hr))
return hr;
hr = session.Open(ds);
if(FAILED(hr))
return hr;
//
// ... Do something with it ...
// ....
session.Close();
ds.Close();
return S_OK;
}
ASKER
Can someone tell me if MFC's CDatabase class is thread safe, it would be much easier for me change my code to CDatabase from CDaoDatabase rather than OLE DB or ADO.
Yes MFC's CDatabase and CRecordset is thread-safe classes. YOu can use them in separate threads without any kind of additional preparations for that.
ASKER
Greetings,
Can someone tell me how I can get rid of the CDatabase object when I am done with it. Here is an abbreviation of the code:
CDatabase * oDb = new CDatabase;
CRecordset rs(oDb);
// run some querries
rs.Close();
oDb->Close();
delete oDb;
However, when my function returns I get an exception because the pointer that CDatabase uses is still valid. This exception happens inside CObject.
Thanks.
By the way, who wants the points
Can someone tell me how I can get rid of the CDatabase object when I am done with it. Here is an abbreviation of the code:
CDatabase * oDb = new CDatabase;
CRecordset rs(oDb);
// run some querries
rs.Close();
oDb->Close();
delete oDb;
However, when my function returns I get an exception because the pointer that CDatabase uses is still valid. This exception happens inside CObject.
Thanks.
By the way, who wants the points
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Great thanks for everything. I decided to use a global database object for all threads and then protect any query executions with critical secitons. I had to minimize the amount of opens and closes because memory was jumping up like crazy. I am still having crashes if implement transaction processing. Are there any problems with using ODBC to get at MS ACCESS rather than DAO. I am using CDatabase so I can have many threads query the db asynchronously
and AfxDaoTerm you program should call automatically, but I see, tham my program not call it, and I call it manually...