void WorkHandler::addWork(Work* w){ printf("WorkHandler::insertWork Thread, insertWork locking \n"); lock(); printf("WorkHandler::insertWork Locked, and inserting into queue \n"); m_workQueue.push(w); signal(); unLock(); }
J’ai suivi un tutoriel et je l’ai eu. Je me demandais s’il était possible de changer l’ordre de singal () et unLock () comme ceci
void WorkHandler::addWork(Work* w){ printf("WorkHandler::insertWork Thread, insertWork locking \n"); lock(); printf("WorkHandler::insertWork Locked, and inserting into queue \n"); m_workQueue.push(w); unLock(); signal(); }
Si je ne peux pas faire cela, pourriez-vous s’il vous plaît me donner des détails, pourquoi je ne suis pas autorisé à le faire? Merci d’avance.
Tout d’abord, il n’y a pas de problème de correction ici. L’un ou l’autre ordre fonctionnera. Rappelez-vous que chaque fois que vous utilisez des variables de condition, vous devez boucler un prédicat en attendant:
pthread_mutex_lock(mutex); while (!predicate) pthread_cond_wait(cvar); pthread_mutex_unlock(mutex);
En signalant après le délocking, vous n’introduisez aucun problème de correction; le thread est toujours garanti pour se réveiller, et le pire des cas est un autre réveil vient en premier – à quel point il voit le prédicat devient vrai et procède.
Cependant, deux problèmes de performances possibles peuvent survenir.
Wakeups parasites. Si vous signalez après le délocking, il est possible qu’un autre thread émette un autre réveil. Considérez le scénario suivant:
Comme vous pouvez le constater, cela peut entraîner un réveil intempestif, susceptible de vous faire perdre du temps processeur.
Personnellement, je ne pense pas que cela vaille la peine de trop s’inquiéter. Vous ne savez pas souvent si votre implémentation prend en charge le déplacement des serveurs de la variable de condition vers la queue du mutex, ce qui est le seul critère réel que vous pouvez utiliser pour décider lequel utiliser.
Mon intuition serait que, si je devais choisir, signaler après le délocking est légèrement moins susceptible d’introduire une inefficacité, car l’inefficacité nécessite une course à trois threads, plutôt qu’une course à deux threads pour le «dépêche-toi et attends». “condition. Cependant, cela ne vaut vraiment pas la peine de s’inquiéter, à moins que les points de repère ne montrent trop de surcharge de changement de contexte.
La réponse à ta question est oui”. En fait, c’est légèrement préférable (comme vous l’avez probablement deviné) car cela évite le problème de «réveiller et d’attendre» de réveiller un thread pour tester une condition et le bloquer immédiatement sur le mutex qu’il doit acquérir avant de tester le état.
Cette réponse est basée sur l’hypothèse que ces choses sont vraies:
lock
est un emballage fin pour pthread_mutex_lock
. unLock
est un wrapper fin pour pthread_mutex_unlock
. signal
est un wrapper pour pthread_cond_signal
. pthread_cond_wait
. Cet article vaut vraiment la peine d’être lu pour répondre à votre question:
Signal avec mutexed ou pas?
En supposant que vous utilisez le même mutex avec la variable conditionnelle pour que le changement de condition soit atomique. Il y a deux cas et vous devriez connaître leur comportement:
Les pthreads sont implémentés avec l’ attente-morphing , c’est-à-dire qu’au lieu de réveiller les threads lors de la signalisation, il ne fait que transférer les threads de variable conditionnelle vers la queue mutex attachée. Le signal lors du locking est donc préférable sans impact trop important sur les performances.
La signalisation avant le délocking du mutex peut provoquer un réveil intempestif. Si votre code n’est pas bien conçu pour gérer les modifications de prédicat apscopes par un réveil parasite, vous devez choisir le signal tout en maintenant le verrou.