Thread pool implementation
Please excuse my brevity, I'm typing on a phone.

Naming

The rules regarding use of leading underscore in identifiers are a bit complex (https://stackoverflow.com/a/228797/2498188). Although you do not have undefined behavior, I do generally recommend that one avoids leading underscore on identifiers as not everyone knows the rules that well.

Consider using std::packaged_task

While your code can be used with any freestanding function without arguments and no return type, by using packaged task you can use any function with bind and you can get a std::future for the return value or synchronisation of the result. It would make your code more generally usable.

Synchronisation

The value _num_work is never used outside of a mutex look and does thus not have to be atomic, in fact you do not need it at all as you can just use the size() method on the queue.

Edit: I see now that it counts the number of tasks including the ones "in flight", I don't really see how this is useful if you don't provide a method for separately querying the number in flight and the number queued.

Effectivity

Note that you do call yield in your thread loop, this doesn't make the thread wait, it only informs the OS that some other thread can run in its place. If there is no other thread to run, it will run again at the top of your loop essentially pegging all of your CPUs at 100% even without any tasks in the queue. You need to use a std::condition_variable to block your worker threads when there is no work to do, and wake them when work arrives.

Desired methods

You're missing don't methods that are typically desirable, like for example the ability to terminate the thread pool with and without waiting for all jobs to complete.

Finally as a reference I offer up my pool in a previous question: Thread pool worker implementation