Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[Multithreading, VC++] Problem z zakleszczaniem

Ostatnio zmodyfikowano 2017-05-13 22:29
Autor Wiadomość
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:
C/C++
bool C_Object::execution_condition_bool = false;
unsigned int C_Object::execution_condition = 0;

- Funkcja synchronizująca:
C/C++
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
C/C++
for(;; ) {
    /*
    Jakiś kod...
    */
    ++C_Object::execution_condition;
    while( !C_Object::execution_condition_bool );
    /*
    Jakiś inny kod...
    */
    ++C_Object::execution_condition;
    while( C_Object::execution_condition_bool );
    /*
    Jeszcze inny kod...
    */
}

Byłbym wdzięczny za pomoc w rozwiązaniu problemu lub zaproponowanie rozwiązania alternatywnego.
P-161010
pekfos
» 2017-05-12 20:00:13
Dlaczego nie używasz specjalnych narzędzi do tego celu? Są dostępne w bibliotece standardowej.
P-161011
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.
P-161013
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.
P-161014
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ć?
P-161018
pekfos
» 2017-05-12 20:58:00
std::condition_variable.
P-161020
Kinexity
Temat założony przez niniejszego użytkownika
» 2017-05-12 21:02:38
dzięki
P-161021
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):
C/C++
#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();
    }
}
P-161022
« 1 » 2
  Strona 1 z 2 Następna strona