> But in the docs, I note this:
> "Any public static (Shared in Visual Basic) members of this type are
> safe for multithreaded operations. Any instance members are not
> guaranteed to be thread safe."
When we say something is not thread safe, it doesn't mean it can't be
used in a thread. It just means that if two threads write the same
object at the same time, you'll get into an undefined state. As long as
the object is used exclusively by a single thread only, you don't have
to worry about thread safety issues. If an object is shared by multiple
threads, you have to ensure mutual exclusivity on your own (for example,
by using a critical section). Most objects are thread unsafe, because
it's a tremendous overhead to add thread safety, and only you can do it
efficienty at the application level. Those who created the objects don't
know anything about your threads and how they interact.
> But that makes the Component Class pretty darn useless for my purpose.
> How do I do thread safe database access?
That has nothing to do with the component, it has to do with the
database. Which database are you using? There are single-user (embedded)
databases, which lock the database while it's open, thus not allowing
anyone else to open it. Those are usually very lightweight databases and
pretty useless in your case. However, every serious database engine
designed for a multiuser environment supports transactions and access to
the engine by multiple threads at the same time.
What you can't do is to drop a single database component on your form,
and access that by multiple threads at the same time. But if you create
a dedicated database logger for each of your threads, they won't
conflict. Your LogItem object should be a private member of your thread,
inaccessible from the outside, and you'll be fine.
In other words, you can access a database by multiple threads, but each
thread has to use its own database component, because the database
access component itself is not thread safe, the database engine usually
is, except those ultra-thin embedded engines.
Tom
Stephen Carson - 06 Apr 2006 20:17 GMT
> > But in the docs, I note this:
> > "Any public static (Shared in Visual Basic) members of this type are
[quoted text clipped - 6 lines]
> the object is used exclusively by a single thread only, you don't have
> to worry about thread safety issues.
You've cleared up my confusion here. I was reading "not thread safe" as
"don't use this in a multi-threaded environment at all".
> > But that makes the Component Class pretty darn useless for my purpose.
> > How do I do thread safe database access?
[quoted text clipped - 6 lines]
> designed for a multiuser environment supports transactions and access to
> the engine by multiple threads at the same time.
We're using SQL Server so I'm sure the database can handle it.
> What you can't do is to drop a single database component on your form,
> and access that by multiple threads at the same time. But if you create
[quoted text clipped - 6 lines]
> access component itself is not thread safe, the database engine usually
> is, except those ultra-thin embedded engines.
OK, I believe my approach is going to work then. The basic idea is that
for each logging request that comes in, a LogItem object is created and
handed off to a thread, like so:
LogItem * logItem = new LogItem(various,info,to,log);
Thread * thread = new Thread ( new ThreadStart( logItem,
&LogItem::LogIt ) );
thread->Start();
The actual database access would happen inside LogIt() with each
logItem object having its own sqlDataAdapter object, etc.
Sound like I'm on the right track?
Thanks very much for your lengthy and very helpful reply!
Stephen W. Carson
Carl Daniel [VC++ MVP] - 06 Apr 2006 20:30 GMT
> Sound like I'm on the right track?
Yes, that should work fine.
You should be aware of potential deadlock issues between multiple database
accessors. For a logging scenario, I'd expect that you'll be using
connections that are in auto-commit mode (no explicit transaction), and that
the loggers will basically be doing insert-only transactions. In that case,
there's nothing to worry about with regard to deadlocks.
-cd
Stephen Carson - 06 Apr 2006 22:52 GMT
> You should be aware of potential deadlock issues between multiple database
> accessors. For a logging scenario, I'd expect that you'll be using
> connections that are in auto-commit mode (no explicit transaction), and that
> the loggers will basically be doing insert-only transactions. In that case,
> there's nothing to worry about with regard to deadlocks.
Insert-only transactions are exactly what I'm planning on doing. Is
there anything special I need to do to ensure my connections are in
"auto-commit mode"? I'm making use of the auto-generated DataSet like
so:
DataRow * newRow = dsTest1->Tables->Item["SWC_Test"]->NewRow();
newRow->Item["French"] = m_temp;
dsTest1->Tables->Item["SWC_Test"]->Rows->Add(newRow);
Carl Daniel [VC++ MVP] - 07 Apr 2006 03:01 GMT
>> You should be aware of potential deadlock issues between multiple
>> database accessors. For a logging scenario, I'd expect that you'll
[quoted text clipped - 6 lines]
> there anything special I need to do to ensure my connections are in
> "auto-commit mode"?
No. Unless you take specific steps to make it otherwise, your connections
will be auto-commit.
-cd
Stephen Carson - 07 Apr 2006 15:27 GMT
Thanks very much to Tamas and Carl for their help. I got a little toy
Web Service working last night that launches off a DB inserting thread
for each request. I then put in a little loop to rapid fire launch 100
of these threads. They all wrote to the database with no problem. 100
in less than a second is way better performance than I expect to need
for this service so this is looking like a robust logging solution.
Stephen W. Carson