-
Scheduling Policy
Hi,
I am trying to learn pthreads and pthreads attributes... I wrote a simple program which creates 2 threads... 1 prints world and another prints hello... I have set priority of the thread which prints hello higher than the other so it should print hello world.. but some how it isn't doing so...
Here's the code...
Code:
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
pthread_mutex_t mutex1;
char *message1 = "Hello";
char *message2 = "World";
void print_Hello( void );
void print_World( void );
int main()
{
pthread_t thread1, thread2;
pthread_attr_t atri1,atri2;
int priority_high=500, priority_low=10;
int status=0;
int t = 25;
struct sched_param para1;
struct sched_param para2;
para1.sched_priority = priority_high;
para2.sched_priority = priority_low;
status = pthread_mutex_init(&mutex1,NULL);
if(status!=0)
{
printf("\nMUTEX init failed !\n");
return 0;
}
status = pthread_attr_init(&atri1);
if(status!=0)
{
printf("\nAttribute init failed !\n");
return 0;
}
status = pthread_attr_init(&atri2);
if(status!=0)
{
printf("\nAttribute init failed !\n");
return 0;
}
status = pthread_attr_setschedpolicy(&atri1, SCHED_RR);
if(status!=0)
{
printf("\nSched policy init failed 1!\n");
return 0;
}
status = pthread_attr_setschedpolicy(&atri2, SCHED_RR);
if(status!=0)
{
printf("\nSched policy init failed 2!\n");
return 0;
}
status = pthread_attr_setschedparam(&atri1, ¶1);
if(status!=0)
{
printf("\nCould not set Priority : 1 !\n");
return 0;
}
status = pthread_attr_setschedparam(&atri2, ¶2);
if(status!=0)
{
printf("\nCould not set priority : 2!\n");
return 0;
}
while(--t>0)
{ status=pthread_create( &thread1, &atri2,(void*)&print_World, NULL);
if(status!=0)
printf("\nThread 1 Could not be created");
status= pthread_create(&thread2, &atri1,(void*)&print_Hello, NULL);
if(status!=0)
printf("\nThread 2 Could not be created");
}
return 0;
}
void print_Hello( void )
{
// while(1)
// {
pthread_mutex_lock(&mutex1);
printf("%s ", message1);
pthread_mutex_unlock(&mutex1);
// }
}
void print_World( void )
{
// while(1)
// {
pthread_mutex_lock(&mutex1);
printf("%s ", message2);
pthread_mutex_unlock(&mutex1);
// }
}
I tried changing scheduling policies, adding / removing mutex but still it keep on printing World Hello World Hello...
So, can anybody suggest what am I doing wrong?
Thanks,
Edesign
-
Yes, you would have to add more locking to ensure that the threads begin to execute in the right order. You could for example have a mutex that is locked by main, then unlocked by thread hello, which the thread world is waiting for.
When you create thread World, it is ready to run, and will get the lock before thread Hello is started.
--
Mats
-
But can't we schedule normal execution order of threads by some means? ( I mean not who'll get the lock first but who'll be executed first kind of schedule..) Once both the threads are in run state shouldn't the one with higher priority execute first?
-
No, there is no guarantee whatsoever of which runs first, second or third between threads when it comes to starting the threads. To ensure ordering, YOU as a programmer will have to use some form of synchronization. This is one part of what makes multithreaded programming hard.
--
Mats
-
I've locked the mutex prior to creating any thread and unlocked it after both of them are created...so now the thread with higher priority should be able to lock the mutex first but still no change in output..
Code:
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <sched.h>
pthread_mutex_t mutex1;
char *message1 = "Hello";
char *message2 = "World";
void print_Hello( void );
void print_World( void );
int main()
{
pthread_t thread1, thread2;
pthread_attr_t atri1,atri2;
int priority_high=500, priority_low=10;
int status=0;
int t = 10;
struct sched_param para1;
struct sched_param para2;
para1.sched_priority = priority_high;
para2.sched_priority = priority_low;
status = pthread_mutex_init(&mutex1,NULL);
if(status!=0)
{
printf("\nMUTEX init failed !\n");
return 0;
}
status = pthread_attr_init(&atri1);
if(status!=0)
{
printf("\nAttribute init failed !\n");
return 0;
}
status = pthread_attr_init(&atri2);
if(status!=0)
{
printf("\nAttribute init failed !\n");
return 0;
}
status = pthread_attr_setschedpolicy(&atri1, SCHED_FIFO);
if(status!=0)
{
printf("\nSched policy init failed 1!\n");
return 0;
}
status = pthread_attr_setschedpolicy(&atri2, SCHED_FIFO);
if(status!=0)
{
printf("\nSched policy init failed 2!\n");
return 0;
}
status = pthread_attr_setschedparam(&atri1, ¶1);
if(status!=0)
{
printf("\nCould not set Priority : 1 !\n");
return 0;
}
status = pthread_attr_setschedparam(&atri2, ¶2);
if(status!=0)
{
printf("\nCould not set priority : 2!\n");
return 0;
}
pthread_mutex_lock(&mutex1);
while(--t>0)
{
status = pthread_create( &thread1, &atri2,(void*)&print_World, NULL);
if(status != 0)
printf("\nThread 1 Could not be created");
status = pthread_create(&thread2, &atri1,(void*)&print_Hello, NULL);
if(status != 0)
printf("\nThread 2 Could not be created");
pthread_mutex_unlock(&mutex1);
}
return 0;
}
void print_Hello( void )
{
// while(1)
// {
pthread_mutex_lock(&mutex1);
printf("%s\n ", message1);
pthread_mutex_unlock(&mutex1);
// }
}
void print_World( void )
{
// while(1)
// {
pthread_mutex_lock(&mutex1);
printf("%s\n ", message2);
pthread_mutex_unlock(&mutex1);
// }
}
-
ok.... I finally got the solution I wanted... first of all I was not setting PTHREAD_EXPLICIT_SCHED ...
Also I needed to move the mutex_lock statement inside while loop...
Now it's working... just for reference I added this piece of code...
Code:
status = pthread_attr_setinheritsched(&atri1, PTHREAD_EXPLICIT_SCHED);
if(status!=0)
{
printf("\nExplicit Sched init failed 1!\n");
return 0;
}
status = pthread_attr_setinheritsched(&atri2, PTHREAD_EXPLICIT_SCHED);
if(status!=0)
{
printf("\nExplicit Sched init failed 2!\n");
return 0;
}
And ya, to set scheduling you need to run the code as root.... :)
@matsp : Thanks a lot... :)
-
I'm pretty sure that's NOT the right solution - particularly if you have to be root to run the code indicates that you are doing something unusual/not right.
Linux, Windows and many other non-RTOS will not have STRICT priorities [1], so the only way to chain different threads is to use locks. Your previous full code post shows that you are using the SAME lock to lock the threads and the ordering thread1 vs thread2 - that still leaves you with a race for which runs when.
I think you need to have a second semaphore/lock to control the order of thread 1 and thread 2, besides the lock to prevent printf from running in parallel [which there likely is one already inside printf, or really weird stuff would happen when printing from multiple threads].
[1] And more importantly, in a modern system with multiple cores, it's quite possible to have more than one thread running at any given time. Which of those threads "get" the lock when you unlock it at main will be completely arbitrary (and undefined) [it may well be predictable in your test app on a particular OS, etc, but generally, but that is the nature of undefined behaviour - it is not a good source of random numbers, it's a good source of "not quite knowing what will happen if something changes!"].
--
Mats
-
Actually I already ordered the threads using semaphores...but I was asked explicitly to make use of scheduling attributes...
I am not sure that I understand you completely, here is what I think the program does..
Before the threads are created main is locking the mutex, than both the threads are created and in run state...but none of them can lock the mutex as it is still not unlocked..
Now it is unlocked by main...so both threads can lock it and execute themselves, but as we've set priority of a particular thead higher than the other the one with higher priority will lock the mutex.. the other thread will have to wait till this thread unlocks the mutex...
Please correct me if my understanding is wrong...
About being root : otherwise thread creation will fail with error no 22 that refers to EINVAL ..
running it as root solves that problem...I read it on some forum, and the reason mentioned was that "To change the default priority, you need to be root", I am not sure what may be the reason otherwise..
Thanks,
Edesign
-
Ok, so if someone told you to use scheduling rather than using explicit locks, then my advice isn't going to be very good.
Yes, you are right, the higher priority thread will take priority. However, if the two threads are both waiting for the lock, and they are BOTH scheduled on two cores in the machine, it still becomes a race-condition, and you can not KNOW that the higher priority thread ACTUALLY gets the lock - they are still racing ahead. Depending on lots of factors (such as which processor gets to run which thread), one will probably win most of the time.
I'm pretty sure that the "unlock/lock" code doesn't look at which thread is higher priority and "gives" the lock to that thread - it allows both threads to run in unlock, and then both will attempt to lock at the same time. One will be first, the other thread will be second - classical race-condition.
I have no experience with scheduling parameters for pthreads, so I can not advice on this. I consider that type of method to be a pretty unreliable source of thread coordination (and it's much harder to look at the thread code itself and understand what is going on, if nothing else), so I have never used such mechanisms.
--
Mats
-
Priority doesn't work that way. Think of the consequences if it did. The highest priority task on the system would get 100% of all resources, and nothing else could ever do anything. Sort of defeats the purpose of multitasking.
Higher priority threads have a tendency to be scheduled more often, and a tendency to cause preemption of a lower priority task when they become runnable, but that's just the average behavior.
Also, trying to guarantee that a specific thread gets the lock first, seems to defeat the purpose of locking. If only thread A is supposed to acquire the lock, why bother having a lock at all? Just let thread A do its thing, and forbid all other threads from doing anything.
Suppose you want the behavior where any thread can acquire the lock, but A always takes priority. This requires either A) lock stealing, where a thread which had a lock suddenly finds itself without it, which would force you to continually check whether you still have the lock before doing anything, which is inherently full of race condition, or B) prediction of the future, and if you figure that one out, please let me know how :)