I am a novice in thread programming. So my apologies for this seemingly stupid question.
This is not novice stuff, not a novice topic, and definitely not a stupid question! This is advanced Linux soft-real-time-related C and C++ programming that requires careful detail and attention.
Every time I run this program, the thread gets created but the default priority (15 in my case).Since I have set the priority to 10 it should start with 10 priority. I can't understand why this is happening.
I had the same problem recently. The solution is that you must also call pthread_attr_setinheritsched(&th_attr, PTHREAD_EXPLICIT_SCHED);
before calling pthread_create()
so that pthread_create()
will use the scheduler settings you set inside the pthread_attr_t
object being passed in rather than inheriting scheduler attributes from the calling thread! If you don't call this function, the default behavior is for pthread_create()
to ignore your scheduler policy and priority settings inside the pthread_attr_t
object, and use the calling thread's scheduler policy and priority instead!
@Lokinin's answer is what helped me figure this out!
Check out the man pages here for pthread_attr_setschedpolicy()
and pthread_attr_setschedparam()
, respectively:
- https://man7.org/linux/man-pages/man3/pthread_attr_setschedpolicy.3.html
- https://man7.org/linux/man-pages/man3/pthread_attr_setschedparam.3.html
Both of those links have this really important blurb here:
In order for the parameter setting made by pthread_attr_setschedpolicy
[or pthread_attr_setschedparam()
] to have effect when calling pthread_create(3)
, the caller must use pthread_attr_setinheritsched(3)
to set the inherit-scheduler attribute of the attributes object attr
to PTHREAD_EXPLICIT_SCHED
.
Then, if you look here for pthread_attr_setinheritsched()
: https://man7.org/linux/man-pages/man3/pthread_attr_setinheritsched.3.html, you'll see (emphasis added):
The inherit-scheduler attribute determines whether a thread created using the thread attributes object attr
will inherit its scheduling attributes from the calling thread or whether it will take them from attr
.
PTHREAD_INHERIT_SCHED
Threads that are created using attr
inherit scheduling attributes from the creating thread; the scheduling attributes in attr
are ignored.
PTHREAD_EXPLICIT_SCHED
Threads that are created using attr
take their scheduling attributes from the values specified by the attributes object.
The default setting of the inherit-scheduler attribute in a newly initialized thread attributes object is PTHREAD_INHERIT_SCHED
.
Let me give you a full demonstration of my own, with full error handling. See Demo 5 inside function set_scheduler()
in my sleep_nanosleep_minimum_time_interval.c demo. In this demo I do the following:
- Memory lock the process's memory into RAM so that it won't go into swap space. If the kernel moves my program's memory into swap space it can cause massive delays and break the soft real-time system I am creating.
- Set the scheduler to the soft real-time
SCHED_RR
round-robin scheduler instead of using the default SCHED_OTHER
round-robin scheduler, since the SCHED_RR
one is a real-time scheduler and therefore has much better and more-reliable nanosecond timing.
- Set the priority to the lowest value of
1
, since just using the soft real-time scheduler already is good enough for me. I don't want to preempt processes I don't have to preempt.
- Create a new pthread with the above scheduler settings, then let it finish and join it back to the main thread.
// -------------------------------------------------------------------------
// Demo 5 (create a pthread with the desired scheduler **policy**
// and **priority** at creation time): if using pthreads: use
// `pthread_attr_setschedpolicy()` and `pthread_attr_setschedparam()` to
// set an initial scheduler **policy** and **priority** at the time of
// thread creation via `pthread_create()`. Don't forget to use
// `pthread_attr_setinheritsched()` to force `pthread_create()` to use our
// new settings instead of inheriting scheduler settings from the calling
// thread! You should use `pthread_attr_init()` and `pthread_attr_destroy()`
// as well to initialize and destroy the attributes object.
// See:
// 1. https://man7.org/linux/man-pages/man3/pthread_attr_init.3.html
// 1. https://man7.org/linux/man-pages/man3/pthread_attr_setschedpolicy.3.html
// 1. https://man7.org/linux/man-pages/man3/pthread_attr_setschedparam.3.html
// 1. https://man7.org/linux/man-pages/man3/pthread_attr_setinheritsched.3.html
// 1. https://man7.org/linux/man-pages/man3/pthread_create.3.html
// 1. https://man7.org/linux/man-pages/man3/pthread_join.3.html
// 1. https://www.drdobbs.com/soft-real-time-programming-with-linux/184402031?pgno=1
// 1. "Listing 2" code which demonstrates some of this code below:
// https://www.drdobbs.com/soft-real-time-programming-with-linux/184402031?pgno=3
// -------------------------------------------------------------------------
{
// 0. Memory lock: also lock the memory into RAM to prevent slow operations
// where the kernel puts it into swap space. See notes above.
retcode = mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT);
if (retcode == -1)
{
printf("ERROR: in file %s: %i: Failed to lock memory into RAM. "
"errno = %i: %s.\n",
__FILE__, __LINE__, errno, strerror(errno));
if (errno == EPERM) // Error: Permissions
{
printf(" You must use `sudo` or run this program as root to "
"have proper privileges!\n");
}
}
else
{
printf("`mlockall()` successful.\n");
}
// 1. Create and initialize a pthread attribute object.
pthread_attr_t pthread_attr;
retcode = pthread_attr_init(&pthread_attr);
if (retcode != 0)
{
printf("ERROR: `pthread_attr_init()` failed. "
"retcode = %i: %s.\n",
retcode, strerror(retcode));
}
// 2. Set the scheduler **policy** (scheduler type) for the next thread
// to be created.
// Set to RR (round robin) soft real-time scheduler.
int scheduler_policy = SCHED_RR;
retcode = pthread_attr_setschedpolicy(&pthread_attr, scheduler_policy);
if (retcode != 0)
{
printf("ERROR: `pthread_attr_setschedpolicy()` failed. "
"retcode = %i: %s.\n",
retcode, strerror(retcode));
}
// 3. Set the scheduler **priority** for the next thread to be created.
const struct sched_param priority_param =
{
// the priority must be from 1 (lowest priority) to 99
// (highest priority) for the `SCHED_FIFO` AND `SCHED_RR`
// (round robin) scheduler policies; see:
// https://man7.org/linux/man-pages/man7/sched.7.html
.sched_priority = 1,
};
retcode = pthread_attr_setschedparam(&pthread_attr, &priority_param);
if (retcode != 0)
{
printf("ERROR: `pthread_attr_setschedparam()` failed. "
"retcode = %i: %s.\n",
retcode, strerror(retcode));
}
// 4. Set the scheduler inheritance attribute so that `pthread_create()`
// will use the scheduler settings set above inside the `pthread_attr`
// object rather than inheriting scheduler attributes from the calling
// thread! If you don't call this function, the default behavior is for
// `pthread_create()` to IGNORE your scheduler policy and priority
// settings inside the `pthread_attr` object, and use the calling
// threads scheduler policy and priority instead!
retcode = pthread_attr_setinheritsched(&pthread_attr,
PTHREAD_EXPLICIT_SCHED);
if (retcode != 0)
{
printf("ERROR: `pthread_attr_setinheritsched()` failed. "
"retcode = %i: %s.\n",
retcode, strerror(retcode));
}
// 5. Create any number of new pthread (POSIX thread) threads with this
// scheduler policy and priority set at thread creation time. Here is
// a demo creating just one pthread.
pthread_t new_thread;
retcode = pthread_create(&new_thread, &pthread_attr,
dummy_pthread_action, "new_thread");
if (retcode != 0)
{
printf("ERROR: `pthread_create()` failed. "
"retcode = %i: %s.\n",
retcode, strerror(retcode));
if (retcode == EPERM) // Error: Permissions
{
printf(" You must use `sudo` or run this program as root to "
"have proper privileges!\n");
}
}
// 6. Destroy the thread attribute object. When done using the
// `pthread_attr_t` attribute object above to create any number of
// pthreads you desire, destroy it, presumably to free up dynamic
// memory and prevent memory leaks.
retcode = pthread_attr_destroy(&pthread_attr);
if (retcode != 0)
{
printf("ERROR: `pthread_attr_destroy()` failed. "
"retcode = %i: %s.\n",
retcode, strerror(retcode));
}
// 7. thread cleanup: wait for the `new_thread` to finish with its
// task by joining with it to wait and then clean it up.
// See: https://man7.org/linux/man-pages/man3/pthread_join.3.html
const char* return_message;
retcode = pthread_join(new_thread, (void**)&return_message);
if (retcode != 0)
{
printf("ERROR: `pthread_join()` failed. "
"retcode = %i: %s.\n",
retcode, strerror(retcode));
}
else
{
printf("`pthread_join()` successful: return_message = \"%s\"\n",
return_message);
}
} // end of Demo 5
See also
- Excellent background reading: https://www.drdobbs.com/soft-real-time-programming-with-linux/184402031?pgno=1
- It has a few errors and is missing a few things, however, such as the fact you need to call
pthread_attr_setinheritsched()
, so for a full set of code examples covering all topics in that article and more, see my function set_scheduler()
in my sleep_nanosleep_minimum_time_interval.c demo.
- Ask Ubuntu: How to run a program with SCHED_RR policy from command line?