I have some code that looks like this:
Thread 0:
CMyOtherClass *m_myclass;
CMyClass::SomeFunc(DWORD SomeParam)
{
m_myclass = new CMyOtherClass(SomeParam);
}
Thread 1:
CMyClass::InsideSecondThread()
{
MySecondThreadFunc(*m_myclass);
}
CMyClass::MySecondThreadFunc(MyOtherClass& myclass)
{
// do something with myclass variable....
// What about thread safety??? Is this not now a shared variable?
// or have we passed a copy and are we safe?
// SomeParam should be the same while in this thread, however it can be changed by Thread 0
}
So my question is, if you are passing this m_myclass variable across threads, is this threadsafe or not?
It is not threadsafe.
It is not threadsafe.
If thread 1 gets executed before the thread 0 creates the object then you end up in accessing NULL pointer in thread 1. ( Assuming m_myclass is initialised to NULL in the constructor)
Another point is :
CMyClass::MySecondThreadFunc(MyOtherClass& myclass)
the myclass object is a shared object and any operations from different threads can create problem.
Unless there is a shared static member, local copy should work for thread safe here.
You can create a new CMyOtherThreadSafeClass which has two members
CMyOtherClass *m_myclass and a CRITICAL_SECTION cs. You should InitializeCriticalSection or better with InitializeCriticalSectionAndSpinCount function in the CMyOtherThreadSafeClass constructor and use EnterCriticalSection and LeaveCriticalSection (see http://msdn.microsoft.com/en-us/library/aa910712.aspx and http://msdn.microsoft.com/en-us/library/ms686908.aspx) everywhere if you need access CMyOtherClass *m_myclass member (read or modify, allocate or free).
You can include a method in CMyOtherThreadSafeClass to make easier to use of EnterCriticalSection and LeaveCriticalSection. If all threads of your program will use EnterCriticalSection and LeaveCriticalSection then your program will be thread safe.
If you call CMyClass::SomeFunc only prior to the second thread being created, then there is no race condition.
Otherwise, it's basically the same problem that prevents double-checked locking from working: The pointer could be assigned to m_myclass prior to the object actually being constructed, and the thread then uses an unconstructed (or partially constructed) object.
It's not threadsafe because both threads are accessing the same bit of memory.
As your code stands, as long as thread 0 allocates the memory before thread 1 starts then you should have no problems because thread 0 doesn't do anything except the allocation. If you change the thread 0 code so it starts modifying the class instance then you'll start to run into issues.
[Edit] Removed my example of what I thought ought to be thread-safe. There's another post here on SO which asks whether changing a pointer is considered an atomic action which is worth a read.
Related
As an example in pseudocode:
MultiThreadedWorker worker;
Foo()
{
const Vector position = CreatePosition();
worker.StartWorker(Position);
}
MultiThreadedWorker::StartWorker(const Vector& myPosition)
{
... Do a bunch of async work that keeps referencing myPosition ...
}
This seems to be working for now, but I don't understand why because it seems that myPosition would end up pointing to nothing long before StartWorker completed.
Assuming this isn't safe, is there any solution other than just passing around everything by value or ensuring it's all on the heap?
std::async copies const references
So yes, it is safe. For a discussion of why it does, see Why does std::async copy its const & arguments?
It is programmers responsibility to ensure that variable live long enough so that it is not destroyed before any access through pointers or references. This can be achieved through at least by one of the following:
Ensure the thread ends before destroying the variable. You can run .join() on the thread before leaving the scope.
Create object on the heap. Create it using make_shared and pass shared_ptr. This ensures the object lives until the last reference is destroyed.
Note that there is another problem with threads and shared objects. If one thread writes when another thread reads to the same object, then it is a data race which is Undefined Behavior. Thread synchronization mechanisms such as std::mutex can be used to avoid this.
I was wondering what would happen in such a class:
class MyClass
{
private:
std::vector<int> iVector;
void Worker()
{
//Lots of stuff done with iVector
//adding, removing elements, etc.
}
}
Let's say I create a thread (invoked by one of the class member functions) that uses iVector and modifies it. Besides this worker, none of the other member functions of the class reads or modifies this std::vector.
Everything seems fine as worker thread is the only one using iVector.
But what would happen when one instance of the object is destroyed? Even if the object is destroyed after the worker thread is finished, destructor for iVector would be invoked from the main thread. Would this lead to undefined behavior?
Thanks!
Firstly I would suggest running a std::join (or your library equivalent) on the thread in the destructor. This will ensure the thread is properly finished and synchronized before the vector destructor runs. This is important as the vector's lifetime must exceed the thread using it.
The C++11 standard and presumably later ones state in 30.3.1.5:
5: Synchronization: The completion of the thread represented by *this
synchronizes with (1.10) the corresponding successful join() return. [
Note: Operations on *this are not synchronized. — end note ]
Now we have to examine 1.10 for more detail, first this section states:
3: The value of an object visible to a thread T at a particular point
is the initial value of the object, a value assigned to the object by
T, or a value assigned to the object by another thread, according to
the rules below.
Honestly, this is difficult to parse, it does not specify exactly what kind of synchronization join offers and seems to imply it synchronizes only the thread itself and not data it has accessed. Therefore I would go the safe route and run atomic_thread_fence(memory_order_acquire) after join in the main thread, and atomic_thread_fence(memory_order_release) in the child thread just before it finishes which should guarantee full happens before semantics and no UB.
If an execution thread is using the ivector class member, and another thread destroys the object with this class member, the continued use of the ivector class member results in undefined behavior.
Even if the object is destroyed after the worker thread is finished,
destructor for iVector would be invoked from the main thread. Would
this lead to undefined behavior?
No. As you've described, this situation is not undefined behavior. The C++ standard does not require an object to be destroyed by the same execution thread that created the object. It's fine for one execution thread to grow, resize the vector, then go away or stop using the vector, and then a different execution thread destroy the entire object.
If I have a class
class A{
A(){
getcontext(context);
makecontext(context, fun1, etc)
put context pointer on queue
}
fun1(args){
something
}
}
In I make an instance of class A in Thread1 running on CPU1, and then try to pop the context off the queue and swap it in from thread2 on CPU2, will there be a problem because the object was instantiated in the stack of Thread1 in CPU1 and hence the pointer to fun1 which is attacked to this context is not reachable?
I'd say the answer is yes and no. All threads share the same memory. If more than 1 thread accesses the object, you need to be careful to synchronize access between thread. That's the yes part.
The no part is when you said stack of thread 1. Stack variables are local to a function. If the function returns, the local variables are no longer valid. You don't show quite enough code for me to see where context gets created, and if the function that allocate the object on the stack waits until thread 2 finishes.
No. The whole point of threads is that they share all memory.
Is it a good and safe practice to lock mutex of the c++ object before delete this object (without unlocking)? I do this to protect possible using of object at this milliseconds from other thread (very low probability).
Will the memory unallocated after that? Is it a good practice?
Example:
ptr_to_delete->MUTEX.lock_writing(); // can not delete session if its already locked. (additational protection)
ptr_to_delete->cleanup();
delete ptr_to_delete;
"I do this to protect possible using of object at this milliseconds from other thread". In this instance, it doesn't really matter if the object's mutex is locked or not - if you've deleted the object in one thread and other threads still have a pointer to it which may be used, you're going to run into trouble.
EDIT:
It's still problematic. As piokuc said, you need to be releasing and freeing the mutex at some point, otherwise your program will be leaking.
There's still the situation where a worker thread and the cleaning thread can obtain a pointer to the object simultaneously. If the cleaning thread deletes the object before the worker thread uses it, you will get undefined behaviour (i.e. a crash).
You should create an accessor function for your array of pointers that only returns a pointer if it's not locked (and locks it before returning). That way, only one thread at a time may have the pointer, and there is no chance of a worker thread obtaining/using a pointer that has been deleted by your cleaning thread.
Pthreads doesn't have a lock_writing function, so it's not possible to review your code without knowing what that does.
However it is undefined behavior to call pthread_mutex_destroy on a mutex that is locked. So, assuming that the destructor of the object does destroy its mutex (either explicitly or as part of the destructor of a data member), you must unlock the mutex before that happens.
If you unlock it in the correct place then your code is correct. If you unlock it in the wrong place then it's incorrect. I can't tell you exactly where the correct place is.
Other thread can get pointer to object from array at the same time
when other thread can get it to delete from array and memory. "Work" thread will always get pointer, then lock mutex, make some work then unlock mutex and loss pointer forever.
Possibly you need a mutex to protect the whole data structure, not just one object in it. It seems to me there is a possible race condition:
Thread 1 Thread 2
get pointer to object from data structure
get ptr from data structure
lock object
cleanup
unlock object
destroy object
lock object (oops, it doesn't exist any more)
let's say we have a c++ class like:
class MyClass
{
void processArray( <an array of 255 integers> )
{
int i ;
for (i=0;i<255;i++)
{
// do something with values in the array
}
}
}
and one instance of the class like:
MyClass myInstance ;
and 2 threads which call the processArray method of that instance (depending on how system executes threads, probably in a completely irregular order). There is no mutex lock used in that scope so both threads can enter.
My question is what happens to the i ? Does each thread scope has it's own "i" or would each entering thread modify i in the for loop, causing i to be changing weirdly all the time.
i is allocated on the stack. Since each thread has its own separate stack, each thread gets its own copy of i.
Be careful. In the example provided the method processArray seems to be reentrant (it's not clear what happens in // do something with values in the array). If so, no race occurs while two or more threads invoke it simultaneously and therefore it's safe to call it without any locking mechanism.
To enforce this, you could mark both the instance and the method with the volatile qualifier, to let users know that no lock is required.
It has been published an interesting article of Andrei Alexandrescu about volatile qualifier and how it can be used to write correct multithreaded classes. The article is published here:
http://www.ddj.com/cpp/184403766
Since i is a local variable it is stored on the thread's own private stack. Hence, you do not need to protect i with a critical section.
As Adam said, i is a variable stored on the stack and the arguments are passed in so this is safe. When you have to be careful and apply mutexes or other synchronization mechanisms is if you were accessing shared member variables in the same instance of the class or global variables in the program (even scoped statics).