Я использую семафоры с разделяемой памятью для связи между несколькими производителями и несколькими клиентами. В моей системе есть два основных типа семафоров: «хранимые семафоры» и «обработанные семафоры».
Система работает следующим образом: производители непрерывно помещают данные в общую память, а затем увеличивают значение сохраненного семафора, пока потребители находятся в цикле, ожидая такой сохраненный семафор. После получения данных от производителя потребители будут обрабатывать такие данные, а затем увеличивать значение обработанного семафора. Производители получат свои результаты, ожидая «обработанного семафора»
Код производителя:
for(int i =0;i<nloop;i++){
usleep(100);
strcpy(shared_mem[i], "data for processing");
sem_post(&shared_mem[i].stored_semaphored);
if(sem_timedwait(&msg_ptr->processed_semaphore,&ts)==-1){ //waiting for result
if(errno == ETIMEDOUT){
}
break;
}else{
//success
}
}
код потребителя:
for (int j = 0; j < MAX_MESSAGE; j++) {
if (sem_trywait(&(shm_ptr->messages[j].stored_semaphore)) == -1) {
if (errno == EAGAIN) {
} else {
//success ==> process data
//post result back on the shared memory, and increase
//the processed semahore
strcpy(shared_mem[j].output, "Processed data");
sem_post(&(shared_mem[j].processed_semaphore));
}
}
}//for loop over MAX_MESSAGE
Моя проблема в том, что цикл for в коде потребителя тратит почти 100% ЦП, потому что в случае отсутствия данных от производителя, цикл for работает непрерывно.
Мой вопрос заключается в том, что есть какие-то другие способы ожидания на наборе семафоров (которые могут быть похожи на механизм ожидания с помощью SELECT, POLL или EPOLL), который не тратит время процессора.
Надеюсь увидеть ваш ответ. Спасибо!
Насколько я знаю, на семафорах ждать нельзя. Это означает, что все обращения должны проходить через один семафор. Вы перебираете множество семафоров, чтобы они вместе могли стать одним объектом. Этот потребитель должен знать, когда какой-либо из семафоров был сигнализирован, поэтому используйте дополнительный sem_post
на новом семафоре, чтобы указать, что набор семафоров изменился.
Ваш код производителя становится примерно таким:
....
sem_post(&shared_mem[i].stored_semaphored);
sem_post(&list_changed_semaphore); /* Wake the consumer. */
....
и потребитель:
/* Block until a consumer has indicated that it has changed the semaphore list */
if (!sem_wait(&list_changed_semaphore)) {
/* At least one producer has signalled a change. */
for (int j = 0; j < MAX_MESSAGE; j++) {
if (sem_trywait(&(shm_ptr->messages[j].stored_semaphore)) == -1) {
}
}
}
Вместо того, чтобы использовать семафор для list_changed_semaphore
Вы могли бы использовать pthread_cond_t
переменная условия, чтобы указать, что что-то в вашем семафоре изменилось. list_changed_semaphore
не должен быть счетчиком, как в примере, показанном здесь, он должен быть только одним битом, чтобы указывать, что производитель изменил список.
Других решений пока нет …