]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Also inline the worker class as a lambda function.
authorWolfgang Bangerth <bangerth@colostate.edu>
Sun, 5 Dec 2021 23:09:09 +0000 (16:09 -0700)
committerWolfgang Bangerth <bangerth@colostate.edu>
Mon, 6 Dec 2021 03:34:03 +0000 (20:34 -0700)
include/deal.II/base/work_stream.h

index 882ca45562788e230198f0fd5948167dc67df036..ecb6c52121806146521e2ccb66de18d5a67db761 100644 (file)
@@ -461,149 +461,6 @@ namespace WorkStream
 
 
 
-      /**
-       * A class that manages calling the worker function on a number of
-       * parallel threads. Note that it is, in the TBB notation, a filter that
-       * can run in parallel.
-       */
-      template <typename Iterator, typename ScratchData, typename CopyData>
-      class TBBWorker
-      {
-      public:
-        using ItemType = typename IteratorRangeToItemStream<Iterator,
-                                                            ScratchData,
-                                                            CopyData>::ItemType;
-
-        /**
-         * Constructor. Takes a reference to the object on which we will
-         * operate as well as a pointer to the function that will do the
-         * assembly.
-         */
-        TBBWorker(
-          const std::function<void(const Iterator &, ScratchData &, CopyData &)>
-            &  worker,
-          bool copier_exist = true)
-          : worker(worker)
-          , copier_exist(copier_exist)
-        {}
-
-
-        /**
-         * Work on an item.
-         */
-        ItemType *
-        operator()(ItemType *&current_item) const
-        {
-          // we need to find an unused scratch data object in the list that
-          // corresponds to the current thread and then mark it as used. if
-          // we can't find one, create one
-          //
-          // as discussed in the discussion of the documentation of the
-          // IteratorRangeToItemStream::scratch_data variable, there is no
-          // need to synchronize access to this variable using a mutex
-          // as long as we have no yield-point in between. this means that
-          // we can't take an iterator into the list now and expect it to
-          // still be valid after calling the worker, but we at least do
-          // not have to lock the following section
-          ScratchData *scratch_data = nullptr;
-          {
-            typename ItemType::ScratchDataList &scratch_data_list =
-              current_item->scratch_data->get();
-
-            // see if there is an unused object. if so, grab it and mark
-            // it as used
-            for (typename ItemType::ScratchDataList::iterator p =
-                   scratch_data_list.begin();
-                 p != scratch_data_list.end();
-                 ++p)
-              if (p->currently_in_use == false)
-                {
-                  scratch_data        = p->scratch_data.get();
-                  p->currently_in_use = true;
-                  break;
-                }
-
-            // if no object was found, create one and mark it as used
-            if (scratch_data == nullptr)
-              {
-                scratch_data =
-                  new ScratchData(*current_item->sample_scratch_data);
-
-                typename ItemType::ScratchDataList::value_type
-                  new_scratch_object(scratch_data, true);
-                scratch_data_list.push_back(std::move(new_scratch_object));
-              }
-          }
-
-          // then call the worker function on each element of the chunk we were
-          // given. since these worker functions are called on separate threads,
-          // nothing good can happen if they throw an exception and we are best
-          // off catching it and showing an error message
-          for (unsigned int i = 0; i < current_item->n_items; ++i)
-            {
-              try
-                {
-                  if (worker)
-                    worker(current_item->work_items[i],
-                           *scratch_data,
-                           current_item->copy_datas[i]);
-                }
-              catch (const std::exception &exc)
-                {
-                  Threads::internal::handle_std_exception(exc);
-                }
-              catch (...)
-                {
-                  Threads::internal::handle_unknown_exception();
-                }
-            }
-
-          // finally mark the scratch object as unused again. as above, there
-          // is no need to lock anything here since the object we work on
-          // is thread-local
-          {
-            typename ItemType::ScratchDataList &scratch_data_list =
-              current_item->scratch_data->get();
-
-            for (typename ItemType::ScratchDataList::iterator p =
-                   scratch_data_list.begin();
-                 p != scratch_data_list.end();
-                 ++p)
-              if (p->scratch_data.get() == scratch_data)
-                {
-                  Assert(p->currently_in_use == true, ExcInternalError());
-                  p->currently_in_use = false;
-                }
-          }
-
-          // if there is no copier, mark current item as usable again
-          if (copier_exist == false)
-            current_item->currently_in_use = false;
-
-
-          // Then return the original pointer
-          // to the now modified object. The copier will work on it next.
-          return current_item;
-        }
-
-
-      private:
-        /**
-         * Pointer to the function that does the assembling on the sequence of
-         * cells.
-         */
-        const std::function<void(const Iterator &, ScratchData &, CopyData &)>
-          worker;
-
-        /**
-         * This flag is true if the copier stage exist. If it does not, the
-         * worker has to free the buffer. Otherwise the copier will do it.
-         */
-        const bool copier_exist;
-      };
-
-
-
       template <typename Worker,
                 typename Copier,
                 typename Iterator,
@@ -642,10 +499,105 @@ namespace WorkStream
               }
           });
 
-        TBBWorker<Iterator, ScratchData, CopyData> worker_filter(worker);
-        auto                                       tbb_worker_filter =
-          tbb::make_filter<ItemType *, ItemType *>(tbb::filter::parallel,
-                                                   worker_filter);
+        auto tbb_worker_filter = tbb::make_filter<ItemType *, ItemType *>(
+          tbb::filter::parallel,
+          [worker =
+             std::function<void(const Iterator &, ScratchData &, CopyData &)>(
+               worker),
+           copier_exist =
+             static_cast<bool>(std::function<void(const CopyData &)>(copier))](
+            ItemType *&current_item) {
+            // we need to find an unused scratch data object in the list that
+            // corresponds to the current thread and then mark it as used. if
+            // we can't find one, create one
+            //
+            // as discussed in the discussion of the documentation of the
+            // IteratorRangeToItemStream::scratch_data variable, there is no
+            // need to synchronize access to this variable using a mutex
+            // as long as we have no yield-point in between. this means that
+            // we can't take an iterator into the list now and expect it to
+            // still be valid after calling the worker, but we at least do
+            // not have to lock the following section
+            ScratchData *scratch_data = nullptr;
+            {
+              typename ItemType::ScratchDataList &scratch_data_list =
+                current_item->scratch_data->get();
+
+              // see if there is an unused object. if so, grab it and mark
+              // it as used
+              for (typename ItemType::ScratchDataList::iterator p =
+                     scratch_data_list.begin();
+                   p != scratch_data_list.end();
+                   ++p)
+                if (p->currently_in_use == false)
+                  {
+                    scratch_data        = p->scratch_data.get();
+                    p->currently_in_use = true;
+                    break;
+                  }
+
+              // if no object was found, create one and mark it as used
+              if (scratch_data == nullptr)
+                {
+                  scratch_data =
+                    new ScratchData(*current_item->sample_scratch_data);
+
+                  typename ItemType::ScratchDataList::value_type
+                    new_scratch_object(scratch_data, true);
+                  scratch_data_list.push_back(std::move(new_scratch_object));
+                }
+            }
+
+            // then call the worker function on each element of the chunk we
+            // were given. since these worker functions are called on separate
+            // threads, nothing good can happen if they throw an exception and
+            // we are best off catching it and showing an error message
+            for (unsigned int i = 0; i < current_item->n_items; ++i)
+              {
+                try
+                  {
+                    if (worker)
+                      worker(current_item->work_items[i],
+                             *scratch_data,
+                             current_item->copy_datas[i]);
+                  }
+                catch (const std::exception &exc)
+                  {
+                    Threads::internal::handle_std_exception(exc);
+                  }
+                catch (...)
+                  {
+                    Threads::internal::handle_unknown_exception();
+                  }
+              }
+
+            // finally mark the scratch object as unused again. as above, there
+            // is no need to lock anything here since the object we work on
+            // is thread-local
+            {
+              typename ItemType::ScratchDataList &scratch_data_list =
+                current_item->scratch_data->get();
+
+              for (typename ItemType::ScratchDataList::iterator p =
+                     scratch_data_list.begin();
+                   p != scratch_data_list.end();
+                   ++p)
+                if (p->scratch_data.get() == scratch_data)
+                  {
+                    Assert(p->currently_in_use == true, ExcInternalError());
+                    p->currently_in_use = false;
+                  }
+            }
+
+            // if there is no copier, mark current item as usable again
+            if (copier_exist == false)
+              current_item->currently_in_use = false;
+
+
+            // Then return the original pointer
+            // to the now modified object. The copier will work on it next.
+            return current_item;
+          });
 
         auto tbb_copier_filter = tbb::make_filter<ItemType *, void>(
           tbb::filter::serial,

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.