pthread_create not working properly with pthread_attr_setschedparam
Asked Answered
M

4

3

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?

Mighty answered 20/2, 2013 at 20:53 Comment(2)
I'm having this exact same problem right now. Did you ever find a solution?Weinshienk
I figured it out. See my answer I just added here.Weinshienk
E
1

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.
Eighteenth answered 10/11, 2015 at 17:44 Comment(1)
Although the code is appreciated, it should always have an accompanying explanation. This doesn't have to be long, but it is expected.Timbre
W
1

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:

  1. https://man7.org/linux/man-pages/man3/pthread_attr_setschedpolicy.3.html
  2. 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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

  1. Excellent background reading: https://www.drdobbs.com/soft-real-time-programming-with-linux/184402031?pgno=1
    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.
  2. Ask Ubuntu: How to run a program with SCHED_RR policy from command line?
Weinshienk answered 7/4, 2022 at 22:9 Comment(0)
I
0

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.

Imputation answered 20/2, 2013 at 21:10 Comment(5)
Yes I am getting the pthread_attr_setschedparam PASSED in my output. I also checked the error values 'EINVAL == ret1' and 'ENOTSUP == ret1'. It shows none of the error logs.Mighty
Huh, that's strange it fails then. I was seeing that call fail, so wondered if that was what you were getting and hadn't noticed the lack of the PASSED output, but it must be something elseImputation
I have edited the question with a new behavior I am seeing. Do you have any explanation for that.Mighty
I can't explain it, sorry. You might want to un-tick my answer to get more attention to the question, I suspect people are more likely to look if it hasn't had an answer yetImputation
Jonathan Wakely. I have a similar scenario. Thread code that works fine on a Linux Red Hat 5.8 and a Linux SuSE Sles10 system, is failing on a Linux Red Hat 6.4 system. I wonder if your failure and spanky's pass is because of the OS's that you two are using.Occlude
S
0

try something like this:

pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
Samal answered 21/2, 2013 at 19:43 Comment(1)
But I want to create the thread with certain attributes. How will detaching the thread help me?Can you please be more elaborate.Mighty

© 2022 - 2024 — McMap. All rights reserved.