LearnMetalCpp examples: why not crashing because of used semaphore?

The examples in LearnMetalCpp do in the renderer's draw method something like this:

  • select a frame for the instance buffer
  • create a new command buffer
  • call dispatch_semaphore_wait to make sure that the selected instance buffer is not used by Metal
  • put dispatch_semaphore_signal into the command buffer's completed handler
  • modify the instance buffer and some other Metal related variables
  • commit the command buffer

Depending on the number of frames used and the complexity of the scene there can be a couple of frames in the command queue. Suppose the window (and its related view) is closed while Metal is still busy with items in the command queue. This means that the semaphore is still in use.

How is it guaranteed that the semaphore is destroyed after the view is closed? Or is it guaranteed that the view's destructor is only called after the command queue has finished all its work?

Great question! In trying to find an answer, I found that the LearnMetalCPP samples don't properly cleanup upon the app's termination; the view delegate and renderer are never destroyed and even if they were, the sample is not calling dispatch_release on the semaphore. We'll need to fix that, but I can tell you how things should work, (but don't actually work in those samples).

Whatever work the app submits to the queue will eventually complete even if the window is closed before it completes, so eventually the semaphore will signal even if the work in the queue never makes it to the screen. The renderer's destructor should release the semaphore and once the semaphore signals, the OS would also release it and it would be destroyed.

LearnMetalCpp examples: why not crashing because of used semaphore?
 
 
Q