Because 16-bit processes multitask cooperatively with respect to each other, 16-bit code is often written with the assumption that it will not be interrupted by another process until it explicitly yields inside the 16-bit scheduler (typically as a result of calling the GetMessage function). In contrast, 32-bit code is written with the expectation that it can be preempted and blocked at any time. A 32-bit application can wait for a synchronization object to be set to the signaled state without impeding the progress of another process. If you mix code written under these different assumptions, you should take care to avoid deadlocks or errors due to unexpected reentrancy.
While a process is executing 32-bit code, it is possible for other processes to enter 16-bit code, possibly reentering the 16-bit code that performed the thunk. That is, entering a 16-bit to 32-bit thunk releases the 16-bit subsystem for use by other processes (under certain conditions noted in the following paragraph). Therefore, you should not use 16-bit to 32-bit thunks if your code cannot be reentered while the thunk code is executing. In addition, you should not use 16-bit to 32-bit thunks inside callback functions passed to a third-party DLL, unless the documentation indicates that the code calling the callback function is reentrant.
If the process executing the thunk is a 32-bit process, any other process can reenter 16-bit code inside a 16-bit to 32-bit thunk. On the other hand, if the process executing the thunk is a 16-bit process, only 32-bit processes can reenter 16-bit code, because 16-bit processes are cooperatively multitasked. Therefore, if your 16-bit code is used only by 16-bit processes, the reentrancy requirement can be relaxed, because other 16-bit processes can be scheduled only if your 16-bit process yields.