9 votes

En attente d'un atomic_bool

J'ai deux threads et un drapeau qui est activé par le second thread. Je pourrais utiliser un atomic_bool mais je veux pouvoir attendre* que le drapeau soit activé sur le premier fil. Comment puis-je le faire ?

Je ne peux pas utiliser un condition_variable Je suppose, parce que si le deuxième fil appelle notify_one avant que le premier fil ne commence à attendre, le fil ne se réveillera pas.

De plus, vérifier si le drapeau a déjà été activé devrait être raisonnablement rapide. Je suppose que cela devrait être assez simple, mais je suis juste coincé, alors je demande ici. Merci d'avance.

*Edit : Blocage bien sûr, pas occupation-attente. Désolé si ce n'était pas clair.

12voto

cooky451 Points 1415

Avec l'aide de cbreak et Ravadre (commentaires) je suis arrivé à partir d'ici :

int main()
{
    std::mutex m;
    std::condition_variable cv;

    std::thread t([&] {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            std::unique_lock<std::mutex> lock(m);
            cv.wait(lock);
            std::cout << "Yay!\n";
    });

    cv.notify_one();
    t.join();
}

Ce qui ne se termine généralement pas du tout, jusqu'ici :

int main()
{
    std::mutex m;
    std::condition_variable cv;
    bool flag = false;

    std::thread t([&] {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::unique_lock<std::mutex> lock(m);
        cv.wait(lock, [&] { return flag; });
        std::cout << "Yay!\n";
    });

    {
        std::lock_guard<std::mutex> lock(m);
        flag = true;
    }

    cv.notify_one();
    t.join();
}

Ce qui fait effectivement le travail, mais semble toujours être beaucoup de frais généraux inutiles. N'hésitez pas à poster une réponse équivalente mais plus performante (ou plus élégante), je l'accepterai avec plaisir. Merci de n'utiliser que le standard C++11, et si non, expliquez pourquoi le standard C++11 ne peut pas faire cela.

Edit : J'ai aussi écrit une classe safe_flag pour encapsuler ceci (merci encore à cbreak) ; n'hésitez pas à suggérer des améliorations.

class safe_flag
{
    mutable std::mutex m_;
    mutable std::condition_variable cv_;
    bool flag_;

public:
    safe_flag()
        : flag_(false)
    {}

    bool is_set() const
    {
        std::lock_guard<std::mutex> lock(m_);
        return flag_;
    }

    void set()
    {
        {
            std::lock_guard<std::mutex> lock(m_);
            flag_ = true;
        }
        cv_.notify_all();
    }

    void reset()
    {
        {
            std::lock_guard<std::mutex> lock(m_);
            flag_ = false;
        }
        cv_.notify_all();
    }

    void wait() const
    {
        std::unique_lock<std::mutex> lock(m_);
        cv_.wait(lock, [this] { return flag_; });
    }

    template <typename Rep, typename Period>
    bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) const
    {
        std::unique_lock<std::mutex> lock(m_);
        return cv_.wait_for(lock, rel_time, [this] { return flag_; });
    }

    template <typename Rep, typename Period>
    bool wait_until(const std::chrono::duration<Rep, Period>& rel_time) const
    {
        std::unique_lock<std::mutex> lock(m_);
        return cv_.wait_until(lock, rel_time, [this] { return flag_; });
    }
};

7voto

Pete Becker Points 27371
bool go = false;
std::mutex mtx;
std::condition_variable cnd;

// waiting thread:
std::unique_lock<std::mutex> lck(mtx);
while (!go)
    cnd.wait(lock);
// when we get here we know that go is true, and we have the lock

// signalling thread:
{
std::unique_lock<std::mutex> lck(mtx);
go = true;
cnd.notify_one();
}
// now we've released the lock, so the waiting thread will make progress

0voto

phoeagon Points 1273

Quelle est exactement votre plate-forme ? Sur les plateformes compatibles avec Posix, nous utilisons

  sem_t semaphore;
  sem_init( &semaphore , 0 , x );

pour obtenir un sémaphore avec une valeur initiale de x. Puis avec

 sem_wait(&semaphore ); sem_post(&semaphore);

vous pouvez synchroniser les deux threads. N'oubliez pas de déclarer semaphore en tant que variable globale pour s'assurer que les deux threads puissent y accéder (ou par tout autre moyen permettant d'obtenir le même résultat).

Pour faire court, vous le pouvez :

sem_t semaphore;
sem_init(&semaphore, 0 , 0 );
void thread2(){
   sem_post(&semaphore);    //second thread --A
}
void thread1(){
    sem_wait(&semaphore);   // wait until thread2() executes line A
}

Il devrait y avoir des utilitaires similaires pour réaliser la même chose sur Win32 aussi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X