[Multithreading, VC++] Problem z zakleszczaniem
Ostatnio zmodyfikowano 2017-05-13 22:29
Kinexity Temat założony przez niniejszego użytkownika |
[Multithreading, VC++] Problem z zakleszczaniem » 2017-05-12 19:35:41 Okoliczności: Stworzyłem program wykonujący pewne obliczenia współbieżnie. Wymagają one synchronizacji, więc dodałem jeden wątek, który je ze sobą synchronizuje. Problem: Przy starcie obliczeni program zakleszcza się od razu na synchronizacji. Kod odpowiedzialny za synchronizację: - Wartości początkowe zmiennych: bool C_Object::execution_condition_bool = false; unsigned int C_Object::execution_condition = 0;
- Funkcja synchronizująca: for(;; ) { while( C_Object::execution_condition < C_Object::num_of_objects ); C_Object::execution_condition_bool = true; C_Object::execution_condition = 0; while( C_Object::execution_condition < C_Object::num_of_objects ); C_Object::execution_condition_bool = false; C_Object::execution_condition = 0; }
- Funkcja licząca for(;; ) { ++C_Object::execution_condition; while( !C_Object::execution_condition_bool ); ++C_Object::execution_condition; while( C_Object::execution_condition_bool ); }
Byłbym wdzięczny za pomoc w rozwiązaniu problemu lub zaproponowanie rozwiązania alternatywnego. |
|
pekfos |
» 2017-05-12 20:00:13 Dlaczego nie używasz specjalnych narzędzi do tego celu? Są dostępne w bibliotece standardowej. |
|
Kinexity Temat założony przez niniejszego użytkownika |
» 2017-05-12 20:06:00 Chciałem ale albo to ja nie rozumiem ich działania, albo nie pasują do mojego problemu. |
|
pekfos |
» 2017-05-12 20:09:02 Samemu tego nie zaimplementujesz. Nie bez wstawek asemblera, lub wyspecjalizowanych funkcji. Mechanizmy z biblioteki standardowej można użyć do wszystkiego, jeśli się rozumie programowanie współbieżne. |
|
Kinexity Temat założony przez niniejszego użytkownika |
» 2017-05-12 20:41:48 Dobra - ujmę to tak: Czego powinienem użyć, aby po wykonaniu danej części kodu wątki oczekiwały na zakończenie tej operacji przez wszystkie pozostałe, by potem kontynuować? |
|
pekfos |
» 2017-05-12 20:58:00 std::condition_variable. |
|
Kinexity Temat założony przez niniejszego użytkownika |
» 2017-05-12 21:02:38 dzięki |
|
Elaine |
» 2017-05-12 21:04:04 W Booście jest boost::barrier, które dokładnie do tego służy. Jeśli nie chcesz wciągać Boosta, to możesz zaimplementować barierę przy pomocy dwóch zmiennych, muteksa i zmiennej warunkowej (optymalniej byłoby semaforem, ale API wątków w bibliotece standardowej jest wybrakowane): #include <condition_variable> #include <iostream> #include <mutex> #include <thread> #include <vector>
class barrier { public: explicit barrier( unsigned int thread_count ); void wait(); private: const unsigned int thread_count; unsigned waiting_thread_count; bool flag; std::mutex mutex; std::condition_variable condvar; };
barrier::barrier( unsigned int thread_count ) : thread_count( thread_count ) , waiting_thread_count( 0 ) , flag( false ) { }
void barrier::wait() { std::unique_lock < std::mutex > guard( mutex ); const bool expected = !flag; ++waiting_thread_count; if( waiting_thread_count == thread_count ) { waiting_thread_count = 0; flag = expected; condvar.notify_all(); } else { condvar.wait( guard,[ & ] { return flag == expected; } ); } }
int main() { std::vector < std::thread > threads; barrier bar( 10 ); std::mutex m; for( int i = 0; i < 10; ++i ) { threads.emplace_back([ &, i ]() { { const std::lock_guard < std::mutex > guard( m ); std::cout << "Worker " << i << " before barrier\n" << std::flush; } bar.wait(); { const std::lock_guard < std::mutex > guard( m ); std::cout << "Worker " << i << " after barrier\n" << std::flush; } } ); } for( auto & thread: threads ) { thread.join(); } }
|
|
« 1 » 2 |