C++ 14 thread pool executor design
this-&gt;threads_.emplace_back(
    std::thread(std::bind(&amp;PoolExecutor::worker, this)));


Creative use of std::bind, but a lambda would have sufficed:

this-&gt;threads_.emplace_back(
    std::thread([this] () { this-&gt;worker() });




void submit(std::function&lt;void()&gt; func)
{
    this-&gt;cv_.notify_all();
}


Why bother waking all worker threads when only a single slice of work was added? std::condition_variable_any::notify_one() is more appropriate.



void stop()
{
    this-&gt;stop_ = true;
}


Here, on the other hand, std::condition_variable_any::notify_all() should have been used, wake the threads currently sleeping.

void stop()
{
    this-&gt;stop_ = true;
    this-&gt;cv_.notify_all()
}




std::shared_lock&lt;std::shared_timed_mutex&gt; lock(this-&gt;mu_, std::try_to_lock);
this-&gt;cv_.wait_for(lock, 10ms);


This part only works as expected for the first thread, as it actually gets the lock. The second thread fails to obtain the lock.

See the documentation for std::condition_variable_any::wait_for. The lock must be locked before entering wait_for.

That means you can't use std::try_to_lock, but actually need std::lock.



While at it, you should get used to using the optional 3rd parameter on wait to pass in a predicate in order to filter spurious wakes:

std::shared_lock&lt;std::shared_timed_mutex&gt; lock(this-&gt;mu_, std::lock);
this-&gt;cv_.wait_for(lock, 10ms, [this] () {return this-&gt;stop_ || !this-&gt;work_queue_.empty());


That predicate is executed before waiting for the first time, so if e.g. this-&gt;stop_ is already set by the time lock is aquired, wait() with the predicate returns immediately without requiring another wake up call.



At this point you can do away with the "timed" stuff as well. You no longer need it. You can now also replace your std::condition_variable_any by the simpler std::condition_variable.

In fact, neither do you need the 2nd mutex either:

std::mutex mu_;
std::condition_variable cv_;

...

bool finished()
{
    std::lock_guard&lt;std::mutex&gt; guard(this-&gt;mu_);
    return this-&gt;working_ == 0 &amp;&amp; this-&gt;work_queue_.empty();
}

void worker()
{
    while(!this-&gt;stop_)
    {
        bool accquired = false;
        {
            std::unique_lock&lt;std::mutex&gt; lock(this-&gt;mu_);
            this-&gt;cv_.wait(lock, [this] () { return this-&gt;stop_ || !this-&gt;work_queue_.empty() );
            if(this-&gt;stop_) break;
            if(!this-&gt;work_queue_.empty())
            {
                func = this-&gt;work_queue_.front();
                this-&gt;work_queue_.pop();
                accquired = true;
                this-&gt;working_++;
            }
        }
        if(accquired)
        {
            func();
            --this-&gt;working_;
        }
    }
}





  Q1. Am I using mutex and lock correctly?


No. Even though it might have even worked, you violated the contract by attempting to wait on an unlocked mutex.


  Q2. It is possible to use single mutex in PoolExecutor class?


As seen above, yes.


  Q3. Is there any ways to wait executor until finished? 


If by "finished" you mean the executor is ready to be destroyed? That is already the case.

Otherwise if you just mean to wait until the pool runs empty? Well, you do have std::atomic_int working_ in there.

All you really need now, is a second condition variable:

void wait() {
    std::unique_lock&lt;std::mutex&gt; lock(this-&gt;mu_);
    this-&gt;cv2_.wait(lock, [this] () {
        return ( this-&gt;working_ == 0 &amp;&amp; this-&gt;work_queue_.empty() ) || this-&gt;stop_
    });
}


Now update the worker to invoke this-&gt;cv2_.notify_all() after decrementing this-&gt;working_ and you are done.