Implementing timeout of a resource (in this case a database connection) I am currently having a problem with too many database connections. Therefore, I am trying to implement a database connection timeout. In the code below the changing of value of the shared resource will be replaced with connecting and disconnecting to the database. I am new to programming with threads and I kindly wonder if I have made any logical errors or if there are any better approaches to this problem? There is no built-in timeout in OCCI which I use.

#include &lt;thread&gt;
#include &lt;chrono&gt;
#include &lt;iostream&gt;
#include &lt;mutex&gt;
#include &lt;atomic&gt;

namespace chrono = std::chrono;

class scoped_thread{
  std::thread t;
public:
  explicit scoped_thread(std::thread t_): t(std::move(t_)){
    if ( !t.joinable()) throw std::logic_error("No thread");
  }
  ~scoped_thread(){
    t.join();
    std::cout &lt;&lt; "Thread " &lt;&lt; std::this_thread::get_id() &lt;&lt; " joined.\n";
  }
  scoped_thread(scoped_thread&amp;)= delete;
  scoped_thread&amp; operator=(scoped_thread const &amp;)= delete;
};

template&lt;typename T&gt;
class LockWrapper {
    T* t;
    std::mutex mut;

public:
    class Proxy {
        T* t;
        std::unique_lock&lt;std::mutex&gt; lock;
        Proxy(LockWrapper&amp; wr) : t(wr.t), lock(wr.mut) { }
        friend LockWrapper;
    public:
        T&amp; operator*() { return *t; }
        T* operator-&gt;() { return t; }
    };
    LockWrapper(T* t) : t(t) {}

    Proxy aquire() { return {*this}; }
};

using clock_type = chrono::system_clock;
using shared_deadline = std::atomic&lt;clock_type::time_point&gt;;
constexpr auto tlim=100;
template&lt;typename T&gt; void timeout(T&amp; shared_resource,const shared_deadline&amp; deadline) {
    while(clock_type::now()&lt;deadline.load())
    {
        constexpr auto sleeping_time=1;
        std::cout &lt;&lt; "Sleeping for another  " &lt;&lt; 1 &lt;&lt; " seconds\n";
        std::this_thread::sleep_until(clock_type::now()+chrono::seconds(1));
    }
    *shared_resource.aquire()=0; // will replace by database disconnect
    std::cout &lt;&lt; "Setting resource to " &lt;&lt; (*shared_resource.aquire()) &lt;&lt; " after timeout occurred in thread " &lt;&lt; std::this_thread::get_id() &lt;&lt; ".\n";
}
int main()
{
    int int_value=1;
    LockWrapper&lt;int&gt; shared_resource(&amp;int_value);
    constexpr auto timeout_length=10;
    auto get_new_deadline=[timeout_length](){return clock_type::now()+chrono::seconds(timeout_length);};
    shared_deadline deadline(get_new_deadline());
    auto th = std::make_unique&lt;scoped_thread&gt;(std::thread(timeout&lt;LockWrapper&lt;int&gt;&gt;, std::ref(shared_resource),std::cref(deadline)));
    constexpr int sleeping_time=20;
    for(auto t=0;t&lt;tlim;t+=sleeping_time) // This loop simulates repeated database access
    {
        std::cout &lt;&lt; "Slept for " &lt;&lt; t &lt;&lt; " seconds. Sleeping for another " &lt;&lt; sleeping_time &lt;&lt; " seconds\n";
        std::this_thread::sleep_for(chrono::seconds(sleeping_time));
        if((*shared_resource.aquire())==0)
        {
            *shared_resource.aquire()=1; // will replace by database connect
            std::cout &lt;&lt; "Setting resource to " &lt;&lt; (*shared_resource.aquire()) &lt;&lt; "\n";
            deadline=get_new_deadline();
            th = std::make_unique&lt;scoped_thread&gt;(std::thread(timeout&lt;LockWrapper&lt;int&gt;&gt;, std::ref(shared_resource),std::cref(deadline)));
        }
        else
        {
            deadline=get_new_deadline();
        }
    }
}
Code


Acquire not aquire.
The scoped_thread move constructor is missing a &amp;, and should have the signature scoped_thread(scoped_thread&amp;&amp;) = delete.
system_clock is the wrong clock type to use, as it's not monotonic (the user can adjust it whenever they choose). steady_clock would probably be the right choice here.
Since scoped_thread stores the thread object as a member, the scoped_thread constructor could use variable template arguments and perfect forwarding, rather than passing in a std::thread object. This makes the user code slightly shorter.
When declaring time constants (tlim, sleeping_time), it would be better to use std::chrono types at the point of declaration, rather than later on in the code, so that the constant has units associated with it directly.
(Style/Opinion:) Vertical spacing makes code easier to read:

using clock_type = chrono::system_clock;
using shared_deadline = std::atomic&lt;clock_type::time_point&gt;;

constexpr auto tlim=100;

template&lt;typename T&gt; void timeout(T&amp; shared_resource,const shared_deadline&amp; deadline)


With a little extra spacing, it's a lot easier to parse this visually as two using declarations, a constant and the start of a function.




Design - locking

There are a couple of places where the resource is locked and then unlocked again rapidly, e.g.:

    if((*shared_resource.aquire())==0)
    {
        *shared_resource.aquire()=1; // will replace by database connect
        std::cout &lt;&lt; "Setting resource to " &lt;&lt; (*shared_resource.aquire()) &lt;&lt; "\n";


Maintaining the lock would be better, otherwise what's printed to std::cout may not be what you expect:

    auto proxy = shared_resource.aquire();

    if (*proxy == 0)
    {
        *proxy = 1; // will replace by database connect
        std::cout &lt;&lt; "Setting resource to " &lt;&lt; *proxy &lt;&lt; "\n";




Design - cancelling / timeout behaviour


If you comment out every line after creating the timeout object:

auto th = std::make_unique&lt;scoped_thread&gt;(std::thread(timeout&lt;LockWrapper&lt;int&gt;&gt;, std::ref(shared_resource), std::cref(deadline)));


main() won't complete until the timeout finishes. This is probably not desirable behaviour.
There is no way to cancel the timeout without manually setting a deadline zero seconds in the future (i.e. dodgy hacks). Furthermore, the fixed sleep of 1 second inside timeout() means you may have to wait up to a second anyway.
Sleeping for one second in a loop seems like strange behaviour, since we know exactly how long we actually need to sleep for before waking up.
It is error-prone to manually increase the deadline every time an operation that requires the connection is used.




Changes

Some of the problems above can be solved by encapsulating the timeout functionality in a class, and using a std::condition_variable to do the timed waiting. This also allows the callback to be cancelled (or called immediately) if desired.

class ThreadedCallback
{
public:

    using clock_t = chrono::steady_clock;
    using duration_t = clock_t::duration;
    using action_t = std::function&lt;void()&gt;;

    ThreadedCallback(duration_t timeout, action_t const&amp; action)
    {
        start(timeout, action);
    }

    ~ThreadedCallback()
    {
        cancel();
    }

    ThreadedCallback(ThreadedCallback&amp;&amp;) = delete;
    ThreadedCallback(ThreadedCallback const&amp;) = delete;

    void restart(duration_t timeout, action_t const&amp; action)
    {
        cancel();

        start(timeout, action);
    }

    void cancel()
    {
        {
            std::lock_guard&lt;std::mutex&gt; lock(m_mutex);

            if (!m_cancelled)
            {
                m_cancelled = true;
                m_cv.notify_one();
            }
        }

        assert(m_thread.joinable());
        m_thread.join();
    }

private:

    void start(duration_t timeout, action_t const&amp; action)
    {
        assert(!m_thread.joinable());
        m_thread = std::thread([=] () { run(timeout, action); });
    }

    void run(duration_t timeout, action_t const&amp; action)
    {
        std::unique_lock&lt;std::mutex&gt; lock(m_mutex);

        m_cancelled = false;
        m_cv.wait_for(lock, timeout, [&amp;] () { return m_cancelled; });

        // note: this check can be removed (and cancel() renamed to call_now()) 
        // or a boolean flag added to cancel() to indicate whether the action should still be called anyway
        if (!m_cancelled)
            action();
    }

    std::thread m_thread;
    std::mutex m_mutex;
    std::condition_variable m_cv;
    bool m_cancelled;
};

int main()
{
    int int_value = 1;
    LockWrapper&lt;int&gt; shared_resource(&amp;int_value);

    auto disconnect = [&amp;] ()
    {
        auto proxy = shared_resource.acquire();
        *proxy = 0; // will replace by database disconnect
        std::cout &lt;&lt; "Setting resource to " &lt;&lt; *proxy &lt;&lt; " after timeout occurred in thread " &lt;&lt; std::this_thread::get_id() &lt;&lt; ".\n";
    };

    auto timeout = std::chrono::seconds(5);
    ThreadedCallback callback(timeout, disconnect);

    constexpr auto tlim = std::chrono::seconds(50);
    constexpr auto sleeping_time = std::chrono::seconds(2);
    for (auto t = std::chrono::seconds(0); t &lt; tlim; t += sleeping_time) // This loop simulates repeated database access
    {
        std::cout &lt;&lt; "Slept for " &lt;&lt; t.count() &lt;&lt; " seconds. Sleeping for another " &lt;&lt; sleeping_time.count() &lt;&lt; " seconds\n";
        std::this_thread::sleep_for(sleeping_time);

        auto proxy = shared_resource.acquire();

        if (*proxy == 0)
        {
            *proxy = 1; // will replace by database connect
            std::cout &lt;&lt; "Setting resource to " &lt;&lt; *proxy &lt;&lt; "\n";

            callback.restart(timeout, disconnect);
        }
        else
        {
            callback.restart(timeout, disconnect);
        }
    }

    std::cout &lt;&lt; "done!" &lt;&lt; std::endl;
}


This still doesn't solve the issue of manually restarting the timer with every access operation. Perhaps a timeout class like this would be better kept in the resource (or LockWrapper) itself.

For example, since we want the time after the last access, the Proxy class destructor could start the timeout (e.g. call a function in the LockWrapper to create a ThreadedCallback in a unique_pointer), and the Proxy constructor could call a function to clear that pointer (cancelling the disconnect operation).

Then the timeout would be directly tied to the access itself, and not have to be reset manually by user code.