Is it safe to transfer (synchronously) stack allocated memory to another thread?

Recently, I heard that the memory on the stack is not shared with another thread, and the memory on the heap is shared with other threads.

I usually do:

HWND otherThreadHwnd; DWORD commandId; // initialize commandId and otherThreadHwnd struct MyData { int data1_; long data2_; void* chunk_; }; int abc() { MyData myData; // initialize myData SendMessage(otherThreadHwnd,commandId,&myData); // read myData } 

Can this be done?

+4
source share
5 answers

I think that two different problems are embarrassed for those who “heard that the memory on the stack is not shared with another thread”:

  • object lifetime - the data on the stack is valid only until the thread leaves the scope of the variable name. In the example, you are giove, you handle this by calling another thread synchronously.

  • visibility of the memory address - pspace addresses for the process are distributed between different threads in the process. Thus, variables addressed by one thread are addressed by other threads in the process. If you pass the address to the thread in another process, the situation is completely different, and you will need to use some other mechanism (which may be for the memory block to be mapped to both processes, but I don’t know, t think that usually can do with stack memory).

+2
source

Yes, in this case it is safe.

Stack data exists only for the lifetime of a function call. Because SendMessage is a synchronous, blocking call, the data will be valid throughout this call.

This code will be broken if you replace SendMessage with a call to PostMessage, SendNotifyMessage or SendMessageCallback, as they will not be blocked, and the function could return before the target window received the message.

+3
source

Yes, everything is in order.

SendMessage works in blocking mode. Even if myData is allocated on the stack, its address is still displayed for all threads in the process. Each thread has its own stack; but the data on the stack can be explicitly shared, for example, by your code. However, as you believe, do not use PostThreadMessage in this case.

+2
source

What you heard about is a “potential privacy violation” that shares data in one thread of a private stack with another thread.

Although this is not recommended, it is only a “potential” problem - with proper synchronization, this can be done safely. In your case, this synchronization is done :: SendMessage (); it will not be returned until the message has been processed in another thread, so the data will not go beyond the main stack of threads. But be careful that no matter what you do with this pointer in the workflow, this should be done before returning from the message handler (if you store it somewhere, be sure to make a copy).

0
source

As others have already said, how you wrote it is fine, and in the general case, nothing will happen right away when you pass a pointer to an object in the stack on another thread until everything is synchronized. However, I tend to compress a bit in this case, because things that seem thread safe can go out of their intended order when an exception occurs, or if one of the threads is associated with asynchronous I / O callbacks. In the case of an exception in another thread during your SendMessage call, it can immediately return 0. If the exception is later handled in another thread, you may have an access violation. Another potential danger is that everything stored on the stack can never be forcibly removed from another thread. If it is stuck waiting for some callback, object, etc. Forever, and the user decided to cancel or exit the application, there is no way for the workflow to be sure that the stalled thread has cleared all objects in its stack.

My point is this: in simple scenarios, as you described, where everything works fine, nothing changes, and no external dependencies work, sharing pointers on the local stack is safe, but since allocating to a bunch is really the same as simple, and this gives you the ability to explicitly control the lifetime of an object from any stream in extenuating circumstances, why not just use a bunch?

Finally, I highly recommend that you be very careful with the void * chunk_ member of your MyData structure, as it is not thread safe, as described if it is copied to another stream.

0
source

Source: https://habr.com/ru/post/1300943/


All Articles