Reputation: 153
I am a novice in thread programming. So my apologies for this seemingly stupid question.
I am trying to create a POSIX thread using pthread_create() using pthread_attr_t. I am trying to set the sched_priority value and put it in the attribute.The code is pasted below:
#include <iostream>
#include <cstring>
#include <pthread.h>
using namespace std;
void* log(void* arg)
{
FILE *fp = fopen("/tmp/log.txt", "w+");
if (fp != NULL)
{
fputs("Logging with Thread", fp);
}
else
{
cout <<"file pointer not created" << endl;
}
return 0;
}
int main(int argc, char** argv )
{
pthread_t th;
pthread_attr_t th_attr;
int policy;
struct sched_param thparam;
memset(&thparam, 0,sizeof(sched_param));
int retval = pthread_attr_init(&th_attr);
if (0 != retval)
{
cout <<"Attribute initialization failed" << endl;
}
thparam.sched_priority = 10;
int ret1 = pthread_attr_setschedparam(&th_attr, &thparam);
if (0 == ret1)
{
cout <<"pthread_attr_setschedparam PASSED" << endl;
}
int ret = pthread_create(&th, &th_attr, log, NULL);
if (0 != ret)
{
cout <<"thread not created" << endl;
}
else
{
cout <<"Thread created" << endl;
}
int retval1 = pthread_getschedparam(th, &policy, &thparam);
if (0 != retval1)
{
cout <<"Inside Main::pthread_getschedparam FAILED at start" << endl;
}
else
{
cout <<"Inside Main::priority: " << thparam.sched_priority << endl;
cout <<"Inside Main::sched policy: " << policy << endl;
}
pthread_join(th, NULL);
return (0);
}
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. All the log messages I am printing are as expected and there seem to be no error. Can anyone please point out what I am doing wrong in the code?
Thanks!!!!
EDIT:
I seem to have found out a interesting thing.I was not able to set the thread priority during thread creation. But I can change the priority of the thread after it is created. I used the API pthread_setschedparam
to set the priority. This time the priority of the thread changed properly. Still can't fathom why this is happening.
I should also mention that I am using an embedded system with ARM arch. I am also setting the scheduler policy to SCHED_RR.
Can some one please explain why this is happening?
Upvotes: 3
Views: 3635
Reputation: 52659
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:
Both of those links have this really important blurb here:
In order for the parameter setting made by
pthread_attr_setschedpolicy
[orpthread_attr_setschedparam()
] to have effect when callingpthread_create(3)
, the caller must usepthread_attr_setinheritsched(3)
to set the inherit-scheduler attribute of the attributes objectattr
toPTHREAD_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 fromattr
.
PTHREAD_INHERIT_SCHED
Threads that are created using
attr
inherit scheduling attributes from the creating thread; the scheduling attributes inattr
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:
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.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.// -------------------------------------------------------------------------
// 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
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.Upvotes: 1
Reputation: 71
From the man pages:
In order for the parameter setting made by 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.
Upvotes: 1
Reputation: 416
try something like this:
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
Upvotes: 0
Reputation: 171263
Are you sure you're seeing this output?
pthread_attr_setschedparam PASSED
You aren't checking the pthread_attr_setschedparam
call for errors, I think it's probably returning EINVAL, and so the priority of the thread hasn't been altered.
The Linux man pages claim that function always succeeds, but that's not true when I tested your code.
Upvotes: 0