PDA

View Full Version : [Linux C] Emulare WaitForSingleObject con timeout


tomminno
20-10-2007, 09:11
Ho provato ad emulare la WaitForSingleObject di Windows usando le pThread, ma ci sono riuscito solo in parte.
Il mio obiettivo è quello di bloccare un thread in attesa di un evento, se però la condizione di wait per un qualche motivo viene impostata dopo il signal (in debug avviene praticamente sempre) ottengo un fallimento per timeout, mentre in Windows viene riconosciuto l'evento come già settato e la WaitForSingleObject ritorna subito.

Questo è il codice che ho usato:

class Event
{
public:
Event()
{
#ifdef WIN32
event = CreateEvent(NULL,false,false,NULL);
#else
pthread_cond_init (&event, NULL);
pthread_mutex_init(&mutex, NULL);
#endif
}
~Event()
{
#ifdef WIN32
CloseHandle(event);
#else
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&event);
#endif
}
void SetEvent()
{
#ifdef WIN32
::SetEvent(event);
#else
pthread_cond_signal(&event);
#endif
}
void ResetEvent()
{
#ifdef WIN32
::ResetEvent(event);
#else
pthread_cond_signal(&event);
#endif
}

bool Wait()
{
#ifdef WIN32
return WaitForSingleObject(event,INFINITE) == WAIT_OBJECT_0;
#else
pthread_mutex_lock(&mutex);
int rc = pthread_cond_wait(&event, &mutex);
pthread_mutex_unlock(&mutex);
return rc == 0;
#endif
}

bool Wait(int milliseconds)
{
#ifdef WIN32
return WaitForSingleObject(event,milliseconds) == WAIT_OBJECT_0;
#else
struct timeval now;
struct timespec timeout;
gettimeofday(&now, NULL);
timeout.tv_sec = now.tv_sec + milliseconds/1000;
timeout.tv_nsec = now.tv_usec * 1000;

bool done = false, success = false;
int rc = pthread_mutex_lock(&mutex);
if (rc) /* an error has occurred */
return false;
while (!done)
{
rc = pthread_cond_timedwait(&event,&mutex,&timeout);
switch (rc)
{
case 0:
success = true;
done = true;
break;
default:
if (rc == ETIMEDOUT)
done = true;
break;
}
}
pthread_mutex_unlock(&mutex);
return success;
#endif
}
private:
#ifdef WIN32
HANDLE event;
#else
pthread_cond_t event;
pthread_mutex_t mutex;
#endif
};


Ok sono pronto alla fucilazione :)

Un altra domanda ma se volessi attendere sulla pthread_cond_timedwait per 1500 millisecondi devo per forza aggiungere 1 al campo tv_sec e 5e8 a tv_nsec?
Non c'è un modo per aggiungere direttamente il valore a tv_nsec?
Quando ho provato ad aggiungere 15e8 al campo tv_nsec non ho mai raggiunto il timeout.

71104
20-10-2007, 10:31
fino a qualche mese fa anche io stavo a combattere con questioni del genere, ma ho fatto in maniera molto diversa: non ho cercato più di tanto di uniformare il codice Linux con quello Win32. nel caso specifico degli eventi, portando su Linux ho parzialmente ristrutturato e utilizzato i pthread signals (alla fine IMHO è più facile fare così che non sbattersi ad inventarsi meccanismi di emulazione).

tomminno
20-10-2007, 13:31
fino a qualche mese fa anche io stavo a combattere con questioni del genere, ma ho fatto in maniera molto diversa: non ho cercato più di tanto di uniformare il codice Linux con quello Win32. nel caso specifico degli eventi, portando su Linux ho parzialmente ristrutturato e utilizzato i pthread signals (alla fine IMHO è più facile fare così che non sbattersi ad inventarsi meccanismi di emulazione).

Non credo di aver cercato di emulare il comportamento di Windows, mi sembra un criterio di sincornizzazione standard: un thread rimane in wait su una condizione per un certo timeout.
Vorrei capire come fare in modo che una condizione di wait possa terminare con successo se per caso il signal è arrivato prima.
Su Windows questo avviene automaticamente senza problemi, su Linux non sono ancora riuscito ad ottenerlo.

Al momento il codice che ho scritto non mi pare dare alcun problema, però è impossibile debuggare proprio per il fatto che in debug finisce che arriva prima il signal e poi il wait.