cura (Si tenga presente che la gestione degli errori delle chiamate pthread sono stati omessi)
È possibile raggiungere questo testando se la coda è piena, con la funzione di lei ha citato nei commenti. Per questa risposta presumo che sia bool is_queue_full(const queue*)
.
Nel tuo caso di test puoi garantire lo scenario 3, creando il produttore e creando un consumatore, se e solo se, dopo che la coda è piena. Come bool is_queue_full (coda *); // non devono utilizzare il mutex in sé, forse segnare solo per uso interno
struct queue {
/* Actual queue stuff */
pthread_mutex_t queue_mutex;
pthread_cond_t read_condvar;
pthread_cond_t write_condvar;
};
void wait_until_queue_is_full (queue *q) {
pthread_mutex_lock(&q->queue_mutex);
while (!is_queue_full(q)){ //Use in loop because of Spurious wakeups
pthread_cond_wait(&q->write_condvar,&q->queue_mutex);
}
pthread_mutex_unlock(&q->queue_mutex);
}
bool test_writer_woke_up(queue *q);
bool test_case(){
queue *q = create_queue();
producer *p = create_producer(q);
wait_until_queue_is_full(q);
return test_writer_woke_up(q); //or cache the result and destroy your queue, but if your testrunner process will quit anyway...
}
wait_until_queue_is_full
sarà solo verificare se la coda è piena, e se no, si aspetta, come ogni lettore, fino a quando il produttore aka produttore ha reso completo.Quindi la tua testcase può produrre i consumatori con qualcosa come test_writer_woke_up
void intern_consume_stuff (coda q);/ La funzione stagista che prende roba dalla coda, ma doesen't a cuore la sychronization aka mutex e condvar */
bool test_writer_woke_up(queue *q){
pthread_mutex_lock(&q->queue_mutex); //Could be omitted in this testcase (together with the 1 unlock below of course)
void intern_consume_stuff(queue *q);
pthread_mutex_unlock(&q->queue_mutex); //Could be omitted in this testcase (together with the 1 lock above of course)
pthread_cond_signal(&q->read_condvar);
/* Adjust these as you like to give your producer/writer time to wake up and produce something
*/
unsigned retry_count = 5;
unsigned sleep_time = 1;
//timed cond wait approach
for (; retry_count > 0; --retry_count){
pthread_mutex_lock(&q->queue_mutex);
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += sleep_time;
int timed_cond_rc = 0;
while (!is_queue_full(q) && timed_cond_rc == 0) {
timed_cond_rc = pthread_cond_timedwait(&q->write_condvar, &q->queue_mutex, &ts);
}
if (is_queue_full(q)) {
pthread_mutex_unlock(&q->queue_mutex);
return true;
}
assert(timed_cond_rc == ETIMEDOUT);
continue;
}
return false;
}
Se hanno utilizzato il tempo assoluto di attesa, perché si doveva ricalcolare tempi relativi, o per semplificare le cose si potrebbe sostituire il ciclo for con questo approccio ingenuo
//naive busy approach
for (; retry_count > 0; --retry_count){
pthread_mutex_lock(q->queue_mutex);
const bool queue_full_result = is_queue_full(q);
pthread_mutex_unlock(q->queue_mutex);
if (queue_full_result){
return true;
} else {
pthread_yield();
sleep(sleep_time);
}
}
Avviare solo il thread del produttore, attendere fino a quando non viene bloccato, quindi avviare l'utente? – EOF
Esistono funzioni API che consentono di testare quando la coda è piena? – Superlokkus
@EOF - Come faccio a sapere a livello di codice che il thread del produttore è ora bloccato? (Sto cercando qualcosa oltre "* aspetta un adeguato periodo di tempo *") –