Use thread_group for improved exception safety (#1785).
authorCarl Hetherington <cth@carlh.net>
Thu, 23 Jul 2020 20:53:43 +0000 (22:53 +0200)
committerCarl Hetherington <cth@carlh.net>
Thu, 23 Jul 2020 20:53:56 +0000 (22:53 +0200)
src/lib/encode_server.cc
src/lib/encode_server.h
src/lib/j2k_encoder.cc
src/lib/j2k_encoder.h

index 8db3f867cc09f34fe97e4f040c1e576f123070a0..c242cb216acac2a45d4a98f3d63d823fc53a2329 100644 (file)
@@ -87,14 +87,9 @@ EncodeServer::~EncodeServer ()
                _full_condition.notify_all ();
        }
 
-       BOOST_FOREACH (boost::thread* i, _worker_threads) {
-               try {
-                       i->join ();
-               } catch (...) {
-
-               }
-               delete i;
-       }
+       try {
+               _worker_threads.join_all ();
+       } catch (...) {}
 
        {
                boost::mutex::scoped_lock lm (_broadcast.mutex);
@@ -241,8 +236,7 @@ EncodeServer::run ()
        }
 
        for (int i = 0; i < _num_threads; ++i) {
-               boost::thread* t = new thread(bind(&EncodeServer::worker_thread, this));
-               _worker_threads.push_back (t);
+               boost::thread* t = _worker_threads.create_thread (bind(&EncodeServer::worker_thread, this));
 #ifdef DCPOMATIC_LINUX
                pthread_setname_np (t->native_handle(), "encode-server-worker");
 #endif
index 91e0075039823f2616e719061ff517d899ed1760..a43cea7efea8228a02a06d063766bd861948477f 100644 (file)
@@ -54,7 +54,7 @@ private:
        void broadcast_thread ();
        void broadcast_received ();
 
-       std::vector<boost::thread*> _worker_threads;
+       boost::thread_group _worker_threads;
        std::list<boost::shared_ptr<Socket> > _queue;
        boost::condition _full_condition;
        boost::condition _empty_condition;
index 3d7b342da42d066958d643c9a64e4ea48a51b36d..49805007394467ecee4836aa95c85c39ce92fa13 100644 (file)
@@ -185,11 +185,7 @@ J2KEncoder::encode (shared_ptr<PlayerVideo> pv, DCPTime time)
 {
        _waker.nudge ();
 
-       size_t threads = 0;
-       {
-               boost::mutex::scoped_lock threads_lock (_threads_mutex);
-               threads = _threads.size ();
-       }
+       size_t threads = _threads->size();
 
        boost::mutex::scoped_lock queue_lock (_queue_mutex);
 
@@ -250,26 +246,20 @@ J2KEncoder::encode (shared_ptr<PlayerVideo> pv, DCPTime time)
 void
 J2KEncoder::terminate_threads ()
 {
-       boost::mutex::scoped_lock threads_lock (_threads_mutex);
+       if (!_threads) {
+               return;
+       }
 
-       int n = 0;
-       BOOST_FOREACH (boost::thread* i, _threads) {
-               /* Be careful not to throw in here otherwise _threads will not be clear()ed */
-               LOG_GENERAL ("Terminating thread %1 of %2", n + 1, _threads.size ());
-               i->interrupt ();
-               try {
-                       i->join ();
-               } catch (exception& e) {
-                       LOG_ERROR ("join() threw an exception: %1", e.what());
-               } catch (...) {
-                       LOG_ERROR_NC ("join() threw an exception");
-               }
-               LOG_GENERAL_NC ("Thread terminated");
-               ++n;
-               delete i;
+       _threads->interrupt_all ();
+       try {
+               _threads->join_all ();
+       } catch (exception& e) {
+               LOG_ERROR ("join() threw an exception: %1", e.what());
+       } catch (...) {
+               LOG_ERROR_NC ("join() threw an exception");
        }
 
-       _threads.clear ();
+       _threads.reset ();
 }
 
 void
@@ -383,11 +373,10 @@ void
 J2KEncoder::servers_list_changed ()
 {
        terminate_threads ();
+       _threads.reset (new boost::thread_group());
 
        /* XXX: could re-use threads */
 
-       boost::mutex::scoped_lock lm (_threads_mutex);
-
 #ifdef BOOST_THREAD_PLATFORM_WIN32
        OSVERSIONINFO info;
        info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
@@ -400,12 +389,11 @@ J2KEncoder::servers_list_changed ()
 
        if (!Config::instance()->only_servers_encode ()) {
                for (int i = 0; i < Config::instance()->master_encoding_threads (); ++i) {
-                       boost::thread* t = new boost::thread (boost::bind(&J2KEncoder::encoder_thread, this, optional<EncodeServerDescription>()));
+                       boost::thread* t = _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, optional<EncodeServerDescription>()));
 #ifdef DCPOMATIC_LINUX
                        pthread_setname_np (t->native_handle(), "encode-worker");
 #endif
-                       _threads.push_back (t);
-#ifdef BOOST_THREAD_PLATFORM_WIN32
+#ifdef DCPOMATIC_WINDOWS
                        if (windows_xp) {
                                SetThreadAffinityMask (t->native_handle(), 1 << i);
                        }
@@ -420,9 +408,9 @@ J2KEncoder::servers_list_changed ()
 
                LOG_GENERAL (N_("Adding %1 worker threads for remote %2"), i.threads(), i.host_name ());
                for (int j = 0; j < i.threads(); ++j) {
-                       _threads.push_back (new boost::thread(boost::bind(&J2KEncoder::encoder_thread, this, i)));
+                       _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, i));
                }
        }
 
-       _writer->set_encoder_threads (_threads.size ());
+       _writer->set_encoder_threads (_threads->size());
 }
index b4542c40a147cca4ccbc62b39f340a5f6a660afe..d56fc1aecd19576c15c96525ce77193fff66d9f9 100644 (file)
@@ -87,9 +87,8 @@ private:
 
        EventHistory _history;
 
-       /** Mutex for _threads */
-       mutable boost::mutex _threads_mutex;
-       std::list<boost::thread*> _threads;
+       boost::shared_ptr<boost::thread_group> _threads;
+
        mutable boost::mutex _queue_mutex;
        std::list<boost::shared_ptr<DCPVideo> > _queue;
        /** condition to manage thread wakeups when we have nothing to do */