-
August 13th, 2011, 03:04 PM
#1
A few questions about thread safety
Hello all,
I have a library with a few classes in it that run great in a single threaded environment, but I am getting more and more into multithreaded apps and even though I havent had problems yet, would like to avoid them by implementing thread safety. I realize it probably would have been better in native c++, but chose to focus on managed c++ when I taught myself and will convert it when I start teaching myself native c++.
Anyways, this was written in ms C++/cli 2008. All of the classes are immutable, once the object is created, it never changes that values. The assignment and math operators all create a new object and return that, however, I do not believe that it is thread safe in that if an instance is assigning itself to a new reference and another thread is reading (or worse assigning a different instance to it) the behavior would appear to be unpredictable. After reading quite a few articles on designing thread safety, I think I have an idea of how to approach it, but I do have a few questions to clear up first.
For example, I know that static methods are shared between all instances, but, are any instance variables created within the method shared also are does each invocation have its own copy? for example:
Code:
static MiniBI^ ModPow(MiniBI^ _base, MiniBI^ _exponent, MiniBI^ _modulus){
MiniBI^ _retval=gcnew MiniBI(); //would this variable be shared or would each invocation create its own instance?
.......rest of algorithm
return _retval;
}
Another question I have is about mutexes. If I create one mutex for the class and call WaitOne() when first entering the method would it allow the same thread to enter a different method within the same class? Example:
Code:
static MiniBI^ operator*(MiniBI^ _val1, MiniBI^ _val2){
_mymutex->WaitOne();
MiniBI^ _retval=gcnew MiniBI();
.....//guts of method
return _retval;
_mymutex->ReleaseMutex();
}
static MiniBI^ Pow(MiniBI^ _base, MiniBI^ _exponent){
_mymutex->WaitOne();
MiniBI^ _retval=gcnew MiniBI();
........
for(int x=0;x<_exponent->Length;x++){
_retval=_retval*_retval; //if this thread is in this method, will the operator* let this thread in to do its work
if(_exponent[x]==1){
_retval=_retval*_base; ///same with this one
}
}
return _retval;
_mymutex->ReleaseMutex();
}
So would the operator* method let the thread through since it allready has control of the mutex in the Pow method? would it still let it through if another thread had allready called WaitOne() in the operator* before it?
All of the operators are overloaded (and static) but, all of them convert the int to a MiniBI^ then call the version of the operator that handles only MiniBI^ values. Example:
Code:
static MiniBI^ operator+(MiniBI^ _val1, MiniBI^ _val2){
_mymutex->WaitOne();
MiniBI^ _retval=gcnew MiniBI();
.....guts of routine
return _retval;
_mymutex->ReleaseMutex();
}
static MiniBI^ operator+(MiniBI^ _val1, int _val2){
MiniBI^ _temp=gcnew MiniBI(_val2);
return _val1+_temp;
}
would the above work correctly? If I have the mutexes only in the methods that return a new reference do I need to use the mutex in the parts that just return a part of the current reference? (in other words read from it). I have been running these classes in simple multithreaded instances without trouble so far, but I have been playing around with vs 2010 and it is pushing them harder, even though I have not been able to point any problems to my classes yet, they do not appear to be thread safe from what I unbderstand so far.
Thanks in advance,
Richard
Last edited by AKRichard; August 13th, 2011 at 03:35 PM.
Reason: didnt mean to post it yet
-
August 13th, 2011, 07:12 PM
#2
Re: A few questions about thread safety
First I must admit that I can't really claim to be an expert on multithreading myself either, so the following may contain mistakes or omissions that then hopefully get corrected by one of those who know better...
Originally Posted by AKRichard
[...] All of the classes are immutable, once the object is created, it never changes that values. The assignment and math operators all create a new object and return that [...].
I never really thought about that yet, but as to my understanduing, immutable classes are thread-safe per se. However, I've never written a class of which I think I could positively claim its immutability, so I always guarded my objects against multithreading issues (only in case I use them in such a context, of course).
I just noticed that this really frequent passage from MSDN docs:
Originally Posted by MSDN
Thread Safety
Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
[...]
actually is not present in the documentation of System::String, which probably is the most prominent example of an immutable class. (I took the quote from the documentation on one of the generic collections. Maybe it actually isn't as ubiquotions as I perceive it and is just specific to those collections, but I use the generic collections quite often which may have distorted my perception.)
[...] however, I do not believe that it is thread safe in that if an instance is assigning itself to a new reference and another thread is reading (or worse assigning a different instance to it) the behavior would appear to be unpredictable. After reading quite a few articles on designing thread safety, I think I have an idea of how to approach it, but I do have a few questions to clear up first.
I believe the immutable object itself to be thread-safe, yet not the tracking handle variable(s) referring to it. So I don't think you need to guard the object itself, but you may need to guard the variables holding its tracking handle or the objects containing these. (However, I have no idea of what you mean by "an instance is assigning itself to a new reference".)
For example, I know that static methods are shared between all instances, but, are any instance variables created within the method shared also are does each invocation have its own copy? for example:
Code:
static MiniBI^ ModPow(MiniBI^ _base, MiniBI^ _exponent, MiniBI^ _modulus){
MiniBI^ _retval=gcnew MiniBI(); //would this variable be shared or would each invocation create its own instance?
.......rest of algorithm
return _retval;
}
Here you need to make a distinction between the MiniBI instance created inside the static function, the tracking handle local to that function pointing to that instance, _retval, and MiniBI instances and their members in general. The MiniBI instance created in the code snippet is singular (IOW a singleton) and of course any reference to a MiniBI that is obtained by calling ModPow() share the same MiniBI instance. There also is only one instance of _retval holding the tracking handle of that particular singular MiniBI instance. However, should construction of MiniBI objects by client code be allowed at all, of course these objects would not share anything with the instance pointed to by _retval or among each other unless they call ModPow() on their own or otherwise access any other static class members.
Another question I have is about mutexes. If I create one mutex for the class and call WaitOne() when first entering the method would it allow the same thread to enter a different method within the same class? [...]
I wouldn't use a Mutex in this scenario at all. Unless you create a separate Mutex for each instance of the class which would be quite tideous, you would be locking on the entire class instead of the individual objects which can be pretty inefficient. For purposes like that I've always used a Monitor which provides a convenient means of locking on the individual objects. There also is the MethodImplAttribute which allows you to actually have the compiler implement the locking for you but I've never used that, among other reasons because I'm not quite certain about the price I'd have to pay for that extra convenience.
(Actually, the Monitor class can be used to lock on classes instead of objects as well, but I don't want to go too much into detail here.)
In fact, I have only used mutexes so far for inter-process protection of global resources. Of course these were system-wide (i.e. named) mutexes.
So would the operator* method let the thread through since it allready has control of the mutex in the Pow method? would it still let it through if another thread had allready called WaitOne() in the operator* before it?
A given thread can lock on a mutex it already owns any number of times it wants without blocking. However, it needs to later release the mutex the same number of times to make it available to other threads again. The same applies to the Monitor.
Last edited by Eri523; August 14th, 2011 at 12:02 AM.
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
-
August 13th, 2011, 07:13 PM
#3
Re: A few questions about thread safety
Originally Posted by AKRichard
All of the classes are immutable, once the object is created, it never changes that values.
If a class is immutable it's threadsafe.
-
August 13th, 2011, 11:46 PM
#4
Re: A few questions about thread safety
Originally Posted by nuzzle
If a class is immutable it's threadsafe.
thats what I had been reading, and all the classes are truly immutable, once an instance is created it never changes, Anytime a change needs to be made, it returns a refernce to a new object. All I was worried about was if a read happened in the middle of an operation working on returning a new object. The read would read an object in a valid state I just wanted to make sure.
The more I think about it, if 2 different threads where working on making a change to the same object at the same time, both would still create valid objects even though I cant think of why someone would have to different threads update the same object, and if one thread is reading the object in the middle of an operation then that would be a race condition huh? as far as the tracking handles not being thread safe, thats not something I would look to taking care of in the class, that should be taken care of on the consumers end.
So just because its thread safe is there anything I am overlooking as to synchronization? or anything else that I may not have thought of?
Thanks,
Richard
-
August 15th, 2011, 02:12 PM
#5
Re: A few questions about thread safety
Originally Posted by AKRichard
So just because its thread safe is there anything I am overlooking as to synchronization? or anything else that I may not have thought of?
To start with make sure you understand the rules with regard to sharing resources between threads:
1) If all threads only access a resource for reading, then no synchronization is required.
2) If at least one thread accesses the shared resource for writing while other other threads access for reading or writing, then synchronization is required.
The above rules imply concurrent access from different threads. If your system prevents concurrent access through some other mechanism, then the above rules may not apply.
So that being said, if you are confident that the objects are immutable, then you probably won't have any issues. I would recommend that you look at the guarding an object at the moment it is being changed (and a new object is being created) to make sure it's thread safe during this time.
Btw, prefer to use the Monitor class over a Mutex unless you need the cross process capabilities of the mutex. The Monitor class (and it's underlying critical section implementation) is going to be more performant than a Mutex.
-
August 15th, 2011, 05:43 PM
#6
Re: A few questions about thread safety
Originally Posted by AKRichard
as far as the tracking handles not being thread safe, thats not something I would look to taking care of in the class, that should be taken care of on the consumers end.
Yeah, that's what I meant to say by...
Originally Posted by me
I believe the immutable object itself to be thread-safe, yet not the tracking handle variable(s) referring to it. So I don't think you need to guard the object itself, but you may need to guard the variables holding its tracking handle or the objects containing these.
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
-
August 19th, 2011, 05:51 AM
#7
Re: A few questions about thread safety
Originally Posted by Arjay
To start with make sure you understand the rules with regard to sharing resources between threads:
1) If all threads only access a resource for reading, then no synchronization is required.
2) If at least one thread accesses the shared resource for writing while other other threads access for reading or writing, then synchronization is required.
The above rules imply concurrent access from different threads. If your system prevents concurrent access through some other mechanism, then the above rules may not apply.
So that being said, if you are confident that the objects are immutable, then you probably won't have any issues. I would recommend that you look at the guarding an object at the moment it is being changed (and a new object is being created) to make sure it's thread safe during this time.
Btw, prefer to use the Monitor class over a Mutex unless you need the cross process capabilities of the mutex. The Monitor class (and it's underlying critical section implementation) is going to be more performant than a Mutex.
but that synchronization would fall to the program creating instances of the class right? (Like what ERI was saying), even if a read occurs while the instance is performing a calculation (Say exponentiation) it would read a valid state since the exponentiation wouldnt return a different value until it had finished and since it returns a new reference, the read would allways read one state or another, not a mixture of the two
-
August 19th, 2011, 04:38 PM
#8
Re: A few questions about thread safety
Originally Posted by AKRichard
but that synchronization would fall to the program creating instances of the class right?
If the original values can change during creation of the new immutable instance, then you should synchronize while creating the instance.
-
August 21st, 2011, 02:49 AM
#9
Re: A few questions about thread safety
Originally Posted by AKRichard
So just because its thread safe is there anything I am overlooking as to synchronization? or anything else that I may not have thought of?
Generally object creation is not threadsafe if you,
1. expose the this pointer from a constructor to another thread, or
2. use a resource in the constructor that's shared among objects of the class.
The first you simply avoid by never exposing the this pointer during object creation.
The second requires that accesses to the shared resource is synchronized or that object creation is synchronized as a whole.
-
August 24th, 2011, 01:41 AM
#10
Re: A few questions about thread safety
Originally Posted by nuzzle
Generally object creation is not threadsafe if you,
1. expose the this pointer from a constructor to another thread, or
2. use a resource in the constructor that's shared among objects of the class.
The first you simply avoid by never exposing the this pointer during object creation.
The second requires that accesses to the shared resource is synchronized or that object creation is synchronized as a whole.
I dont have to worry about either one of those problems, I just got done going completely through the entire namespace and believe it is good. Now I can move on to questions about multithreading in particular which Ill do in another post.
Thanks for taking the time to answer the questions
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|