Re: Atomic Reference Counting - Do you think this would be useful to Boost?
Peter Dimov wrote:
James Kanze wrote:
Chris Thomasson wrote:
I don't think the following contrived scenario is valid with
shared_ptr<...>. Please correct me if I am wrong:
(pseudo-code)
static shared_ptr<app> g_app(new app(...))
static shared_ptr<foo> g_foo;
void a_number_of_threads() {
for(...) {
// I don't think the following is atomic in current shared_ptr<...>:
shared_ptr<foo> l_foo(g_foo);
I can't see any reason why it should be. I can't imagine any
use where it wouldn't lead to a programming error later.
This is the reader-writer problem. One scenario is
void reader()
{
shared_ptr<foo> local( g_foo );
// use local to compute something
}
void writer()
{
shared_ptr<foo> local( g_foo );
shared_ptr<foo> next( new foo( *local ) );
local.reset();
next->update();
g_foo = next; // race here
}
One could put a fast reader-writer lock around g_foo, of
course, but it wouldn't be truly lock-free.
Well, the context requires memory synchronization, and something
to ensure the atomicity of the update of g_foo.
But it begs the point. I can easily image abstract, constructed
cases where you'd need some sort of locking or synchronization.
I can't find any practical application for them, however.
Consider, for example, what you might want if g_foo pointed to
configuration data, read from a file. Your writer function
detects that the configuration file has changed (i.e. a newer
time stamp, or there was a signal telling the program to
rereaded it). At this point, however, it is important that any
given transaction see a coherent view of the configuration. And
within a transaction, it's quite possible that there are several
"readers". So you'll probably want to synchronize the writer
with the transaction logic, at a higher level. And this is the
case for every scenario that I can think of. My impression is
that when dealing with global data, shared_ptr is a bit too low
level; you need something higher level (and once you've got it,
shared_ptr becomes caduc).
Also, of course, global variables don't normally hold critical
resources that must be freed in a timely manner. So you can
just use ordinary pointers, and let the Boehm collector do the
cleaning up. No reason to introduce extra complexity.
Where a shared_ptr is useful for managing global data, IMHO, is
where you have a singleton. Calling instance() acquires a lock,
and returns a shared_ptr whose "destructor" frees the lock. It
is, perhaps, somewhat dangerous, in that anyone keeping a
pointer blocks the entire system, but then, anyone keeping a
pointer needs the lock, no matter how you manage it, and so will
block the system anyway.
--
James Kanze GABI Software
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]