ogs
ogs

Reputation: 1239

C multithreading process with an unexpected cpu consuption

I would like to implement a multithreading process which is in charge of launching threads in parallel.

According to htop's output, each thread consumes less than 1% CPU but the main consumes around 100% CPU.

int main (int argc, char *argv[])
{
    struct sigaction action;
    int i;
    exitReq = 0;
    memset(&engine, 0, sizeof(stEngine_t));
    engine.NbTasks = 12;

    engine.TaskThread = malloc(engine.NbTasks * sizeof(stTask_t));

    /* NbTasks = 12 */
    for (i = 0; i < engine.NbTasks; i++) {
        engine.TaskThread[i] = array[i];
        engine.TaskThread[i].initTask();
        pthread_create(&engine.TaskThread[i].tId, NULL, my_handler, (void *) &engine.TaskThread[i]);
    }

    while (!exitReq) {
        //.. do stuff as reading external value (if value < limit => exitReq = 1)
        sched_yield();
    }

    for (i = 0; i < engine.NbTasks; i++) {
        (void)pthread_cancel(engine.TaskThread[i].tId);
        pthread_join(engine.TaskThread[i].tId, NULL);
        engine.TaskThread[i].stopTask();
        engine.TaskThread[i].tId = 0;
    }
    free(engine.TaskThread);
    memset(&engine, 0, sizeof(stEngine_t));          
    return 0;
}

static void* my_handler(void* params)
{
    stTask_t* ptask = (stTask_t*) params;

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

    while (!exitReq) {
        ptask->launchTask();
        pthread_testcancel();
    }
    pthread_exit(NULL);
}

The sched_yield man page says "sched_yield() causes the calling thread to relinquish the CPU.", that's why it has been used inside the loop.

I probably misunderstood something about the sched_yield() function, but is there a better and more reliable way to relinquish the CPU in this specific situation.

Upvotes: 2

Views: 166

Answers (2)

code_fodder
code_fodder

Reputation: 16341

I believe another take on this is that sched_yield(); is basically the same as Sleep(0);. Where:

A value of zero causes the thread to relinquish the remainder of its time slice to any other thread that is ready to run. If there are no other threads ready to run, the function returns immediately, and the thread continues execution.

(ok, yes this is from MSDN - but it explains it well enough)

Pretty much as Luis de Arquer mentions (+1 there). But this is not usually an optimal approach - i.e. its usually a "bit of a hack" to tell the OS to do its job as you want it to.

Not that it probably really matters much and I have done it plenty in the past for little apps... but you can try using pthread_cond_wait(); to do the waiting and pthread_cond_broadcast() or pthread_cond_signal() to wake up, with - or with so many threads, maybe a semaphore - where each thread signals when it is finished so the main can continue... you have a few options here.

Upvotes: 2

Luis de Arquer
Luis de Arquer

Reputation: 387

sched_yield() doesn't put your thread to sleep. It just pushes it back to the end of the threads queue to be run by the CPU. However, your thread is still a running thread, and will be put to run again as soon as there are no other threads before in the queue.

What happens is, if your thread is the only running one in the queue, it will be rescheduled immediately every time, using 100% of the CPU.

Probably you want to put your thread to sleep, either by calling sleep directly, or block-waiting for some event (e.g. poll())

Upvotes: 4

Related Questions