What should C program do in idle time when running on Linux?
Asked Answered
V

3

6

I've written many C programs for microcontrollers but never one that runs on an OS like linux. How does linux decide how much processing time to give my application? Is there something I need to do when I have idle time to tell the OS to go do something else and come back to me later so that other processes can get time to run as well? Or does the OS just do that automatically?

Edit: Adding More Detail My c program has a task scheduler. Some tasks run every 100ms, some run every 50 ms and so on. In my main program loop i call ProcessTasks which checks if any tasks are ready to run, if none are ready it calls an idle function. The idle function does nothing but it's there so that I could toggle a GPIO pin and monitor idle time with an O'scope... or something if I so desired. So maybe I should call sched_yield() in this idle function???

Viscera answered 16/8, 2012 at 16:37 Comment(0)
G
6

How does linux decide how much processing time to give my application

Each scheduler makes up its own mind. Some reward you for not using up your share, some roll dices trying to predict what you'll do etc. In my opinion you can just consider it magic. After we enter the loop, the scheduler magically decides our time is up etc.

Is there something I need to do when I have idle time to tell the OS to go do something else

You might call sched_yield. I've never called it, nor do I know of any reasons why one would want to. The manual does say it could improve performance though.

Or does the OS just do that automatically

It most certainly does. That's why they call it "preemptive" multitasking.

Gabrila answered 16/8, 2012 at 16:41 Comment(3)
So the other answers say to use sleep(). Should I call sleep() and sched_yield()? if so, in which should be called first?Viscera
@Viscera Read the manual. Yield will leave your process running if there's nothing else to do whereas sleep will unequivocally cause your process to wait.Gabrila
if you're implementing a spinlock, you want to call sleep(0) or sched_yield() every time the lock fails to be taken.Norseman
A
5

It depends why and how you have "idle time". Any call to a blocking I/O function, waiting on a mutex or sleeping will automatically deschedule your thread and let the OS get on with something else. Only something like a busy loop would be a problem, but that shouldn't appear in your design in any case.

Your program should really only have one central "infinite loop". If there's any chance that the loop body "runs out of work", then it would be best if you could make the loop perform one of the above system functions which would make all the niceness appear automatically. For example, if your central loop is an epoll_wait and all your I/O, timers and signals are handled by epoll, call the function with a timeout of -1 to make it sleep if there's nothing to do. (By contrast, calling it with a timeout of 0 would make it busy-loop – bad!).

Agent answered 16/8, 2012 at 16:43 Comment(2)
i added more info to my questionViscera
@PICyourBrain: It sounds like you could do all that with epoll. Timers can be set up via timerfd, and I suppose other events could also be handled via file descriptors. Sleeping on an epoll_wait is an efficient way of passing idle time.Agent
H
1

The other answers IMO are going into too much detail. The simple thing to do is:

while (1){
    if (iHaveWorkToDo()){
        doWork();
    } else {
        sleep(amountOfTimeToWaitBeforeNextCheck);
    }
}

Note: this is the simple solution which is useful in a single-threaded application or like your case where you dont have anything to do for a specified amount of time; just to get something decent working. The other thing about this is that sleep will call whatever yield function the os prefers, so in that sense it is better than an os specific yield call.

If you want to go for high performance, you should be waiting on events.

If you have your own events it will be something like follows:

Lock *l;
ConditionVariable *cv;

while (1){
    l->acquire();
    if (iHaveWorkToDo()){
        doWork();
    } else {
        cv->wait(lock);
    }
    l->release();
}

In a networking type situation it will be more like:

while (1){
    int result = select(fd_max+1, &currentSocketSet, NULL, NULL, NULL);
    process_result();
}

Helmand answered 16/8, 2012 at 16:53 Comment(5)
waitForSomeEvent instead of just sleepCoen
@Coen yea, I was trying the second part as you commented that. I'm just trying to give a few different solutions for people who dont want to delve into the multithreading world too far. it also seems from the question that he is looking for sleep.Helmand
@Helmand I'm guessing you mean l->acquire and l->release, right?>Viscera
Also, in your first example if instead of 'sleep(amountOfTimeToWaitBeforeNextCheck);' you just did nothing, that would be bad?Viscera
@Viscera yea, that would cause a spin loop which would pin the processor to 100% usage, that is the purpose of the sleep. i.e. to yield to some other process.Helmand

© 2022 - 2024 — McMap. All rights reserved.