J'écris un serveur de jeu de nuage de latence zéro. C'est un pipeline de logiciels. Dans la première étape, nous capturons l'écran et dans la deuxième étape, nous l'encodons à la vidéo.Comment éviter la famine de fil
Cependant, après un certain laps de temps, la deuxième étape gèle. J'ai essayé de nombreuses approches indépendantes de la plate-forme, mais dans la veine, l'une ou l'autre gèlera éventuellement. La réponse de How to prevent threads from starvation in C++11 a déclaré que nous devrions utiliser mutex. Je l'ai essayé. Et ça peut durer plus longtemps mais ça gèle parfois (rarement). Je pense que le mutex n'est pas un indice explicite pour empêcher la famine de fil aussi. (peut-être que je fais mal?)
Maintenant, j'utilise mutex et désactiver la fonctionnalité de priorité de Windows en même temps, mais je n'aime pas du tout cette solution. Quelqu'un pourrait-il fournir un exemple de producteur et consommateur sans faim (mieux en C++ 11)?
producteur:
while(Streamer.IsConnected()) {
uint8_t *pBits = Streamer.AcquireNext();
// The buffer is full
if(pBits && get_counter(&fps_limiter) >= 1000/args.m_MaxFps && check_target_window(args.m_TargetWindow.c_str(), limit, &rect)) {
BROFILER_FRAME("MainLoop")
start_counter(&fps_limiter);
if(!FAILED(capture_screen(g_DXGIManager, rect, pBits)))
Streamer.PushNext();
}
else {
this_thread::yield();
// lower cpu usage
Sleep(1);
continue;
}
if (get_counter(&bit_rate) >= 1000) {
uint32_t bps = Streamer.GetBitRate();
printf("\rBirate: %u bps, %u Bps\t\t\t\t\t", bps, bps/8);
start_counter(&bit_rate);
}
}
consommateur:
while(!m_ServerShouldStop) {
uint8_t *data = AcquireLast();
if (!data) {
this_thread::yield();
Sleep(1);
continue;
}
// encoder callback
uint8_t *out;
uint32_t size = m_Encoder(data, &out);
PopLast();
// If encoder output something, send it immediately
if(size>0) {
// send the size of buffer
int res1 = ::send_whole_buffer(client_sck, reinterpret_cast<uint8_t *>(&size),
sizeof(size));
// then the contents
int res2 = ::send_whole_buffer(client_sck, out, size);
bytes += size;
if (m_EventHandler)
m_EventHandler->onFrameSent();
// If any of them fails....
if(!res1||!res2)
break;
}
if (get_counter(&counter) >= 1000) {
m_Bps = bytes * 8;
bytes = 0;
start_counter(&counter);
}
}
...
Au départ, je n'ai pas fait la protection de la file d'attente circulaire. Je pense qu'il n'y a pas de condition de concurrence (un producteur et un consommateur). Puis j'essaye d'ajouter le mutex mais rien ne change ...
Je suggère de prendre des traces de pile de ce que font les threads. Si un thread est assis dans une fonction comme WaitForSingleObject, cela devrait vous donner un indice. Faites quelques traces de pile dans une rangée pour être sûr. – Steve
J'utilise un profileur appelé brofiler (disponible sur github). Il va accrocher Windows APiI. Je n'ai pas appelé explicitement WaitForSingleObject. mais il semble que le fil va y entrer. (Mais il reviendra) –
Hmm, non, si * vraiment * était un problème de famine, alors supprimer la fonction boost est exactement la mauvaise chose à faire. Vous cachez un problème de blocage, très mauvaise idée. Les verrous producteur-consommateur sont facilement disponibles chez Boost et le winapi (InitializeSRWLock etc), n'écrivez pas les vôtres. –