khanhhh89
khanhhh89

Reputation: 317

how to wait effectively on a set of semaphore?

I'm using semaphores with shared-memory for communicating between multi-producers and multi-clients. There are two main kinds of semaphores in my system, which are "stored semaphores" and "processed semaphores".

The system run as following: Producers continously put data into the shared-memory, and then increase the stored semaphore's value, while the consumers is in the loop, waiting for such stored semaphored. The consumers, after receiving data from producer, will process such data and then, increase the processed semaphore's value. Producers will get their results by waiting on "processed semaphore"

The producer code:

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
    }

}

the consumer code:

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

My problem is that the for loop in the consumer code is wasting almost 100 % CPU because in the case of no data from producer, this for loop run continously.

My question is that there is any other ways for waiting on a set of semaphores, (which may be similar to the waiting mechanism by SELECT, POLL, or EPOLL), which does not waste CPU time.

Hope see your answer. Thanks so much!

Upvotes: 1

Views: 1842

Answers (1)

Austin Phillips
Austin Phillips

Reputation: 15766

As far as I know there isn't a way to wait on a set of semaphores. This means that all accesses need to be funnelled through a single semaphore. You're looping over a set of semaphores, so they collectively can become one object. That consumer needs to know when any of the semaphores has been signalled, so use an additional sem_post on a new semaphore to signal that the set of semaphores has changed.

Your producer code becomes something like this:

....
sem_post(&shared_mem[i].stored_semaphored);
sem_post(&list_changed_semaphore); /* Wake the consumer. */
....

and 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) { 
        }
    }
}

Instead of using a semaphore for list_changed_semaphore you could use a pthread_cond_t condition variable to signal that something in your set of semaphores has changed. The list_changed_semaphore does not need to be a counter as the example shown here, it only needs to be a single bit to indicate that a producer has modified the list.

Upvotes: 1

Related Questions