]> SALOME platform Git repositories - modules/smesh.git/commitdiff
Salome HOME
[bos #42217][EDF 28921] Horseshoe with bodyfitting.
authorKonstantin Leontev <Konstantin.LEONTEV@opencascade.com>
Mon, 5 Aug 2024 11:57:49 +0000 (12:57 +0100)
committerKonstantin Leontev <Konstantin.LEONTEV@opencascade.com>
Mon, 5 Aug 2024 11:57:49 +0000 (12:57 +0100)
Fixed endless loop of creating threads and crash for an edge case when num of threads greater than num of hexaedrons to compute.

src/StdMeshers/StdMeshers_Cartesian_3D_Grid.hxx

index 3cf439aa3434b27f18610d5f90579c015eac82e9..8ac347c524cfbafd12b198070a674a8b11ec14ce 100644 (file)
@@ -517,23 +517,66 @@ namespace Cartesian3D
 
   // Implement parallel computation of Hexa with c++ thread implementation
   template<typename Iterator, class Function>
-  void parallel_for(const Iterator& first, const Iterator& last, Function&& f, const int nthreads = 1)
+  void parallel_for(const Iterator& first, const Iterator& last, Function&& f, const unsigned int nthreads = 1)
   {
-      const unsigned int group = ((last-first))/std::abs(nthreads);
+    MESSAGE("Start parallel computation of Hexa with c++ threads...");
 
-      std::vector<std::thread> threads;
+    assert(nthreads > 0);
+
+    const unsigned int numTasksTotal = last - first;
+    std::vector<std::thread> threads;
+    Iterator it = first;
+
+    MESSAGE("Number of elements to compute: " << numTasksTotal << "; num of threads: " << nthreads);
+
+    // Distribute tasks among threads
+    if (numTasksTotal <= nthreads)
+    {
+      // A simple case - just one task executed in one thread.
+      // TODO: check if it's faster to do it sequentially
+      threads.reserve(numTasksTotal);
+      for (; it < last; ++it)
+      {
+        threads.emplace_back(f, std::ref(*it));
+      }
+    }
+    else
+    {
+      // Calculate how to distribute elements among threads evenly
+      const unsigned int numTasksInThread = numTasksTotal / nthreads;
+      MESSAGE("Number of tasks in thread: " << numTasksInThread);
+
+      // Store the numbers of tasks per thread
+      std::vector<unsigned int> distTasksInThreads(nthreads, numTasksInThread);
+
+      // Distribute a remainder among saved numbers
+      const unsigned int remainder = numTasksTotal % nthreads;
+      MESSAGE("Remainder of tasks " << remainder << " will be evenly distributed among threads");
+      for (unsigned int i = 0; i < remainder; ++i)
+      {
+        ++distTasksInThreads[i];
+      }
+
+      // Create threads for each number of tasks
       threads.reserve(nthreads);
-      Iterator it = first;
-      for (; it < last-group; it += group) {
-          // to create a thread 
-          // Pass iterators by value and the function by reference!
-          auto lambda = [=,&f](){ std::for_each(it, std::min(it+group, last), f);};
-
-          // stack the threads 
-          threads.push_back( std::thread( lambda ) );
+      for (const auto i : distTasksInThreads)
+      {
+        Iterator curLast = it + i;
+
+        // Pass iterators by value and the function by reference!
+        auto lambda = [=,&f](){ std::for_each(it, curLast, f); };
+
+        // Create a thread
+        threads.emplace_back(lambda);
+
+        // Advance iterator to the next step
+        it = curLast;
       }
-      std::for_each(it, last, f); // last steps while we wait for other threads
-      std::for_each(threads.begin(), threads.end(), [](std::thread& x){x.join();});
+    }
+
+    std::for_each(threads.begin(), threads.end(), [](std::thread& x){ x.join(); });
+
+    MESSAGE("Parallel computation was finished successfully");
   }
 
   // --------------------------------------------------------------------------