Can just reading a global be thread unsafe?

G

greg wellman

I'm trying to track down a problem in code written by someone else.
The symptom appears to be a form of thread unsafety. Let me write a
little psuedo code

bool firsttime = true;
(some more global declarations)

AnInitFunctionThatEveryThreadRuns()
{
if (firsttime)
{
firsttime = false;
(initialize more globals)
}
}

Now here's the situation - sometimes hours after the first thread, and
many others, have been through this code, two new threads are started
pretty much simultaneously. One would think that because firsttime is
now false, that this function can't do anything so it doesn't matter
that it's technically thread unsafe. However, the globals it
initializes are changing value when these two new threads start and I
can't figure out why.
There is no other place in code that alters those globals, just a
couple that read them. Obviously the problem can't be reproduced while
debugging.

Any ideas?
TIA,
Greg
 
P

Phlip

To answer your Subject line: Yes. Google "volatile".

greg said:
I'm trying to track down a problem in code written by someone else.

And tell them to Google "global variable", to receive the scolding they so
richly deserves. It's probably on WikiPedia by now.
The symptom appears to be a form of thread unsafety. Let me write a
little psuedo code

bool firsttime = true;
(some more global declarations)

AnInitFunctionThatEveryThreadRuns()
{
if (firsttime)
{
firsttime = false;
(initialize more globals)
}
}

Now here's the situation - sometimes hours after the first thread, and
many others, have been through this code, two new threads are started
pretty much simultaneously. One would think that because firsttime is
now false, that this function can't do anything so it doesn't matter
that it's technically thread unsafe. However, the globals it
initializes are changing value when these two new threads start and I
can't figure out why.
There is no other place in code that alters those globals, just a
couple that read them. Obviously the problem can't be reproduced while
debugging.

Yep. Make the global volatile, and the threads might stop clobbering it.

Next, use a real semaphore, instead of a dumb 'bool', so the OS will support
its volatility. And ask questions about semaphores on a newsgroup covering
programming your OS kernel, because we are only qualified here to discuss
raw C++, which has no thread library.
 
I

Ian Collins

greg said:
I'm trying to track down a problem in code written by someone else.
The symptom appears to be a form of thread unsafety. Let me write a
little psuedo code

bool firsttime = true;
(some more global declarations)

AnInitFunctionThatEveryThreadRuns()
{
if (firsttime)
{
firsttime = false;
(initialize more globals)
}
}

Now here's the situation - sometimes hours after the first thread, and
many others, have been through this code, two new threads are started
pretty much simultaneously. One would think that because firsttime is
now false, that this function can't do anything so it doesn't matter
that it's technically thread unsafe. However, the globals it
initializes are changing value when these two new threads start and I
can't figure out why.
There is no other place in code that alters those globals, just a
couple that read them. Obviously the problem can't be reproduced while
debugging.
<OT> if you are using pthreads, use pthread_once </OT>

This sort of question is better asked on comp.programming.threads.
 
J

Joe Seigh

greg said:
I'm trying to track down a problem in code written by someone else.
The symptom appears to be a form of thread unsafety. Let me write a
little psuedo code

bool firsttime = true;
(some more global declarations)

AnInitFunctionThatEveryThreadRuns()
{
if (firsttime)
{
firsttime = false;
(initialize more globals)
}
}

Now here's the situation - sometimes hours after the first thread, and
many others, have been through this code, two new threads are started
pretty much simultaneously. One would think that because firsttime is
now false, that this function can't do anything so it doesn't matter
that it's technically thread unsafe. However, the globals it
initializes are changing value when these two new threads start and I
can't figure out why.
There is no other place in code that alters those globals, just a
couple that read them. Obviously the problem can't be reproduced while
debugging.

It's commonly called Double Checked Locking (DCL) used often to initalize
singletons. It can't be done correctly in a multi-threaded environment
using standard C/C++ alone.

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
 
P

Pete Becker

greg said:
I'm trying to track down a problem in code written by someone else.

Now here's the situation - sometimes hours after the first thread, and
many others, have been through this code, two new threads are started
pretty much simultaneously. One would think that because firsttime is
now false, that this function can't do anything so it doesn't matter
that it's technically thread unsafe. However, the globals it
initializes are changing value when these two new threads start and I
can't figure out why.
There is no other place in code that alters those globals, just a
couple that read them. Obviously the problem can't be reproduced while
debugging.

You've gotten the knee-jerk answers that double checked locking doesn't
work. That doesn't seem to be the problem here, though. New threads see
all the changes made by their creator. If all the previous threads are
handling this correctly, the change to firsttime has propogated through.
To convince yourself, lock a mutex at the beginning of the init function
and unlock it at the end. See if the problem goes away. I'll bet it
doesn't. It's more likely to be memory corruption from a bad pointer.
Writing multithreaded code doesn't mean the most common sources of bugs
are no longer present.
 
G

greg wellman

Pete said:
You've gotten the knee-jerk answers that double checked locking doesn't
work. That doesn't seem to be the problem here, though. ....

Thanks for the perspective. It turned out to be simpler than that.
When I saidI had missed something. The something turned out to be
straightforwardly thread-unsafe manipulation of one of the globals. I
replaced all the globals with members of a class that each thread has
one instance of.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,792
Messages
2,569,639
Members
45,353
Latest member
RogerDoger

Latest Threads

Top