Re: Is code a safe thread?
Kai-Uwe Bux wrote:
Nephi Immortal wrote:
I customize operator new to create my own definition.
m_out_of_memory is a global variable of class Test. m_out_of_memory
can be set to true or false inside operator new function before Test()
is called to construct three data members: a, b, c.
If m_out_of_memory is to be true, then Test() is not called and all
data members cannot be initialized.
My one question is ? is thread safe? What happen if two main
functions are running on two threads at the same time while accessing
m_out_of_memory?
First thread will report out of memory before second thread will skip
to initialize data members. Can you please confirm that it never
happened as long as thread safety is taken care?
Well, it would be impossible to take care of thread safety with the
interface design presented below. The content of the shared static
variable is meant to indicate the status returned by the _previous_
allocation attempt. Hence, the meaning of the variable would differ from
thread to thread (as they go through different allocation attempts and
there is no trans-thread meaning of "last"). No synchronization would
change that. The only way to deal with it, would be to stop any other
threads when it tries to allocate memory until the first thread doing so
has checked the status of _its_ last allocation attempt. Such
synchronization is not possible with the interface you present.
Oops, maybe my imagination was too limited. I could think of something like
this:
class Test {
...
void* operator new ( size_t size ) {
lock the static variable m_out_of_memory;
...
}
static
bool last_alloc_ok ( void ) {
bool result = ...
unlock the static variable m_out_of_memory
return result;
}
...
};
Note, however, that this intimately ties the observer function and the
allocation function. You now must use them strictly alternating in each
thread.
Also, you can leave the locking issues to the calling threads.
Neither solution seems to be appealing: they look much too error-prone.
Or?is m_out_of_memory stored in separate memory on each thread and is
never shared?
Which data are shared depends on the particulars of the thread model.
E.g., in linux you could use multiple processes or multiple threads. In
the later case, static data would be shared.
I choose this method to avoid using exception.
Aha. And what's wrong with exceptions here?
class Test
{
public:
Test() : a( 1 ), b( 2 ), c( 3 ) {
}
~Test() {
}
bool Is_Sufficient_Memory() const {
return ( m_out_of_memory == false ) ? true : false;
}
void* operator new( size_t size ) {
void* p = malloc( size );
m_out_of_memory = ( p == 0 ) ? true : false;
return p;
}
void operator delete( void* memory ) {
free( memory );
}
void Set_abc( int _a, int _b, int _c ) {
a = _a; b = _b; c = _c;
}
private:
static bool m_out_of_memory;
int a;
int b;
int c;
};
bool Test::m_out_of_memory = false;
int main()
{
Test* T = new Test();
if( T->Is_Sufficient_Memory()) {
Hm .....
If the allocation via new() above fails, then T is 0 here and
dereferencing the pointer is undefined behavior. And yes, accessing a
member function qualifies as dereferencing even when the member function
only accesses static data.
T->Set_abc( 10, 20, 30 );
delete T;
}
return 0;
}
One more question: why do not use a nothrow allocation function. In that
case, a new expression would indicate an allocation failure not via an
exception but by returning 0. You can test for that. No threading issues
arise.
Best,
Kai-Uwe Bux