What Is Process Scheduling?
When you run multiple programs at the same time on Linux — a browser, a terminal, a music player — they all share the same CPU(s). But the CPU can only execute one instruction at a time per core. The Linux kernel has a component called the scheduler that continuously decides which process should run next.
The default model Linux uses is called round-robin time-sharing. Think of it like a teacher in a classroom giving each student exactly 30 seconds to speak before moving to the next student. Each process gets a short burst of CPU time — called a time slice or quantum — and then the next process gets its turn.
Time Slice
Time Slice
Time Slice
Again
Again
Repeats
This satisfies two important requirements:
Every process gets a share of the CPU. No process is permanently ignored.
A process does not wait too long before it gets CPU time again.
What Is the Nice Value?
Even in a round-robin system, sometimes you want one process to get more CPU time than others — for example, a video encoder is more important than a background log archiver. Linux provides the nice value for this purpose.
The nice value is a number that belongs to each process. It ranges from -20 (highest priority — gets more CPU) to +19 (lowest priority — gets less CPU). The default nice value for any new process is 0.
The name “nice” comes from the idea of being polite: a process that sets itself to a high nice value (+19) is being “nice” to other processes by voluntarily asking for less CPU time.
fork() and preserved across exec(). So if a shell has nice value +10, its child processes also start at +10.getpriority() and setpriority()
These two system calls let you read and change the nice value of a process, process group, or all processes belonging to a user.
#include <sys/resource.h>
/* Returns the nice value (possibly negative) of the specified process,
or -1 on error */
int getpriority(int which, id_t who);
/* Sets the nice value. Returns 0 on success, -1 on error */
int setpriority(int which, id_t who, int prio);
The ‘which’ Argument
The which argument tells the kernel what kind of entity you are referring to:
| which value | Meaning of ‘who’ | who = 0 means |
|---|---|---|
| PRIO_PROCESS | A single process ID | The calling process itself |
| PRIO_PGRP | A process group ID | The calling process’s group |
| PRIO_USER | A real user ID | The calling process’s real UID |
getpriority() can legitimately return -1 as a valid nice value (when priority is -1). To detect an actual error, you must set errno = 0 before the call and check both the return value and errno afterwards.RLIMIT_NICE: Allowing Unprivileged Priority Raises
Since kernel 2.6.12, Linux added RLIMIT_NICE. This resource limit allows unprivileged processes to raise their own priority (lower nice value) up to a certain ceiling. The formula is:
Example: if RLIMIT_NICE soft limit = 25, then the process can raise its nice value up to 20 − 25 = -5. The useful range of RLIMIT_NICE is 1 (low) to 40 (high).
The Legacy nice() Function
Before setpriority() was standardized, there was a simpler function called nice(). It just adds an increment to the calling process’s current nice value.
#include <unistd.h>
/* Adds 'incr' to the calling process's nice value.
Returns the new nice value on success, or -1 on error. */
int nice(int incr);
nice() is still available but superseded by setpriority() because:
setpriority()can target other processes, process groups, and userssetpriority()sets an absolute value instead of a relative incrementsetpriority()is part of the POSIX standard
The command-line tools nice(1) and renice(8) are the shell equivalents of these system calls.
💻 Code Example 1: Get and Set Nice Value
This program reads the nice value of the current process, changes it, and reads it again.
/* nice_demo.c
* Demonstrates getpriority() and setpriority() on the calling process.
* Compile: gcc nice_demo.c -o nice_demo
* Run: ./nice_demo (normal user: can only raise nice value)
* sudo ./nice_demo (root: can lower nice value too)
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/resource.h>
int main(void)
{
int current_nice;
int new_nice;
/* Step 1: Read current nice value.
* IMPORTANT: set errno = 0 before calling getpriority()
* because it can return -1 as a valid (non-error) result.
*/
errno = 0;
current_nice = getpriority(PRIO_PROCESS, 0); /* 0 = calling process */
if (current_nice == -1 && errno != 0) {
perror("getpriority");
exit(EXIT_FAILURE);
}
printf("Current nice value: %d\n", current_nice);
/* Step 2: Set a new nice value.
* Unprivileged users can only increase (worsen) their nice value.
* Root can set any value from -20 to +19.
*/
if (setpriority(PRIO_PROCESS, 0, 10) == -1) {
perror("setpriority (trying to set to 10)");
exit(EXIT_FAILURE);
}
printf("Successfully set nice value to 10\n");
/* Step 3: Read back to confirm */
errno = 0;
new_nice = getpriority(PRIO_PROCESS, 0);
if (new_nice == -1 && errno != 0) {
perror("getpriority after set");
exit(EXIT_FAILURE);
}
printf("New nice value confirmed: %d\n", new_nice);
/* Step 4: Try to set a high priority (needs root) */
if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
perror("setpriority (trying -10, needs root)");
/* Not a fatal error — just informational */
} else {
errno = 0;
new_nice = getpriority(PRIO_PROCESS, 0);
if (new_nice == -1 && errno != 0) {
perror("getpriority");
} else {
printf("Raised priority to nice value: %d (you are root!)\n", new_nice);
}
}
return EXIT_SUCCESS;
}
Current nice value: 0
Successfully set nice value to 10
New nice value confirmed: 10
setpriority (trying -10, needs root): Permission denied
💻 Code Example 2: Change Priority of Another Process
This example shows how to read and change the priority of a process given its PID on the command line.
/* t_setpriority.c
* Usage: ./t_setpriority <which> <who> <prio>
* which: p = process, g = process group, u = user
* who: PID / PGID / UID (0 = calling process/group/user)
* prio: nice value to set (-20 to +19)
*
* Example: ./t_setpriority p 1234 5
* Sets process 1234's nice value to 5.
*
* Compile: gcc t_setpriority.c -o t_setpriority
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/resource.h>
int main(int argc, char *argv[])
{
int which, prio;
id_t who;
if (argc != 4) {
fprintf(stderr, "Usage: %s [p|g|u] <who> <prio>\n", argv[0]);
fprintf(stderr, " p = process, g = process group, u = user\n");
exit(EXIT_FAILURE);
}
/* Parse the 'which' argument */
switch (argv[1][0]) {
case 'p': which = PRIO_PROCESS; break;
case 'g': which = PRIO_PGRP; break;
case 'u': which = PRIO_USER; break;
default:
fprintf(stderr, "Invalid which: use p, g, or u\n");
exit(EXIT_FAILURE);
}
who = (id_t) atoi(argv[2]);
prio = atoi(argv[3]);
printf("Setting nice value for %s %d to %d...\n",
(which == PRIO_PROCESS) ? "PID" :
(which == PRIO_PGRP) ? "PGID" : "UID",
(int)who, prio);
/* Attempts to set outside range [-20, +19] are silently clamped */
if (setpriority(which, who, prio) == -1) {
perror("setpriority");
exit(EXIT_FAILURE);
}
/* Read back to verify — must guard against -1 being valid */
errno = 0;
prio = getpriority(which, who);
if (prio == -1 && errno != 0) {
perror("getpriority");
exit(EXIT_FAILURE);
}
/* Note: if which is PRIO_PGRP or PRIO_USER, getpriority()
* returns the highest priority (lowest numeric nice value)
* among all matching processes.
*/
printf("Actual nice value now: %d\n", prio);
return EXIT_SUCCESS;
}
./t_setpriority p 0 5 — Set calling process to nice 5./t_setpriority p 1234 10 — Set PID 1234 to nice 10 (must be same user)sudo ./t_setpriority p 1234 -5 — Raise priority (root only)🎯 Interview Questions
getpriority() can legitimately return -1 as a valid nice value (when a process has priority level -1). The standard way to detect errors — checking for a -1 return — would give a false alarm. Setting errno = 0 before the call and then checking if (return == -1 && errno != 0) correctly distinguishes a valid -1 result from an error.RLIMIT_NICE resource limit allows an unprivileged process to raise its priority up to the ceiling defined by 20 − rlim_cur. For example, if RLIMIT_NICE = 25, the process can lower its nice value to as low as -5.getpriority() returns the nice value of the process with the highest priority — that is, the lowest numerical nice value among all matching processes.nice(1) is used to launch a new command with a specified nice value (e.g., nice -n 10 ./myjob). Unprivileged users can lower priority; root can raise it. renice(8) changes the nice value of an already-running process by its PID. The superuser can use renice to adjust any process’s priority.fork() and is also preserved across exec(). This means if you run a shell with nice +5 and launch a program from it, the program also starts with nice +5.