It has been awhile, but I've done this in the past. You can try working with locks, I did that with networking so a file being written to couldn't be accessed by another party until the write process was completed.
As for SHELL, I think I did this: Write a second QB64 program that has the SHELL, without _dontwait in it and have it run minimized or hidden. Call SHELL _dontwait to that QB64 program. Monitor that program in your main program loop, to see when it is closed. A simple way to do that is to have the main program make a temporary file, just before it shells to the second Qb64 (Shell operations) program, and have the second program kill that file, after it completes the shell, and before it closes and terminates with the SYSTEM command.
So something along the lines of...
'Main Program...
' PROGRAM LOOP
' Other program stuff...
IF flag
THEN flag
= 0:
' Do whatever you need with it, now that you know the SHELL process has completed.
'----------------------------
'Second QB64 Program
I haven't revisited this for about 4 years, so I hope I recalled it correctly. I also remember there was some glitch I had to tweak, but I cannot recall what that glitch was. Anyway, it's simple enough to test You can also check into the QB64 _SCREENHIDE command, if you want to run that second program hidden, instead of or as well as minimized.
I may have also figured out another method, but I just can't recall it at this time. Also, someone else might post something that doesn't require a second dependent program be made. For instance, with Windows systems, I would think you could use an API library to get the handle of that SHELL procedure, and then directly monitor it until it no longer existed.
Pete