2017-03-29 3 views
1

J'ai une application multi-thread qui utilise le GPU, qui est intrinsèquement monothread, et les véritables API que j'utilise, cv::gpu::FAST_GPU, se bloque quand j'essaie de les utiliser multi-thread, donc en gros je:Acquérir conditionnellement un std :: mutex

static std::mutex s_FAST_GPU_mutex; 

{ 
    std::lock_guard<std::mutex> guard(s_FAST_GPU_mutex); 
    cv::gpu::FAST_GPU(/*params*/)(/*parameters*/); 
} 

maintenant, l'analyse comparative du code me montre FAST_GPU() dans l'isolement est plus rapide que le CPU FAST(), mais dans l'application réelle de mes autres threads passent beaucoup de temps d'attente pour la serrure, de sorte que le général le débit est pire.

En regardant à travers la documentation, et at this answer il semble que cela pourrait être possible:

static std::mutex s_FAST_GPU_mutex; 
static std::unique_lock<std::mutex> s_FAST_GPU_lock(s_FAST_GPU_mutex, std::defer_lock); 

{ 
    // Create an unlocked guard 
    std::lock_guard<decltype(s_FAST_GPU_lock)> guard(s_FAST_GPU_lock, std::defer_lock); 
    if (s_FAST_GPU_lock.try_lock()) 
    { 
     cv::gpu::FAST_GPU(/*params*/)(/*parameters*/); 
    } 
    else 
    { 
     cv::FAST(/*parameters*/); 
    } 
} 

Cependant, cela ne compile que std::lock_guard accepte seulement std::adopt_lock. Comment puis-je l'implémenter correctement?

+1

Je ne suis pas Bien sûr, vous utilisez un 'unique_lock' statique, car vous ne voudriez généralement pas que 2 threads aient accès au même' unique_lock'. Cela dit, je voudrais supprimer le s_FAST_GPU_LOCK, puis utiliser 'std :: try_to_lock', et tester s'il a réussi à utiliser' owns_lock'. –

+0

@DaveS Ahh, je vois - 'mutex.try_lock()' puis 'lock_guard <> (std :: adopt_lock)'? S'il vous plaît faites cela en une réponse. –

Répondre

9

Il est réellement dangereux d'avoir un unique_lock accessible à partir de plusieurs threads en même temps. Je ne suis pas familier avec la partie opencv de votre question, donc cette réponse est centrée sur l'utilisation du mutex/lock.

static std::mutex s_FAST_GPU_mutex; 
{ 
    // Create a unique lock, attempting to acquire 
    std::unique_lock<std::mutex> guard(s_FAST_GPU_mutex, std::try_to_lock); 
    if (guard.owns_lock()) 
    { 
     cv::gpu::FAST_GPU(/*params*/)(/*parameters*/); 
     guard.unlock(); // Or just let it go out of scope later 
    } 
    else 
    { 
     cv::FAST(/*parameters*/); 
    } 
} 

Cette tente d'acquérir le verrou, si elle réussit, utilise FAST_GPU, puis libère le verrou. Si la serrure était déjà acquis, puis descend la deuxième branche, invoquant FAST

+0

Cela semble bien et suit de plus près le modèle de l'affaire simple, donc devrait être plus facile à comprendre que mes suggestions. –

+0

Eh bien, il s'avère que la version CPU pure est plus rapide que d'essayer ce qui précède pour diviser le travail. Il fonctionne comme vous le décrivez, il est donc temps de sortir le profileur GPU pour voir si autre chose monopolise le GPU. –

+2

Je ne peux pas dire avec certitude, mais le travail va certainement forcer un décrochage de mémoire tampon sur le GPU chaque fois que le processeur touche les données, car il doit ré-uploader ces données pour travailler, ce décrochage de commande peut provoquer le GPU opération à bloquer à l'intérieur de la serrure, en fonction de la mise en œuvre. –

5

Vous pouvez utiliser std::lock_guard, si vous adoptez le mutex dans l'état verrouillé, comme celui-ci:

{ 
    if (s_FAST_GPU_mutex.try_lock()) 
    { 
     std::lock_guard<decltype(s_FAST_GPU_lock)> guard(s_FAST_GPU_mutex, std::adopt_lock); 
     cv::gpu::FAST_GPU(/*params*/)(/*parameters*/); 
    } 
    else 
    { 
     cv::FAST(/*parameters*/); 
    } 
}