Scheduling Policy
Often in a multithreaded system, more threads exist than processors available to run them. The scheduling policy attribute contains the policy that the system uses in selecting threads to run on available processors.
Threads can exist in several states as explained below and illustrated in Figure 18.
*A thread becomes runnable when created, unless explicitly created in a stopped state.
*Eventually, a runnable thread is selected, or dispatched, for execution on a processor and becomes active.
*While executing, a thread can block waiting on a synchronization resource such as a mutex or condition variable.
*Once the synchronization resource releases the thread, it is awakened and again enters the runnable state.
*If a higher-priority thread become runnable while a lower-priority thread is active, the lower-priority thread is preempted and returned to the runnable state so that the higher-priority thread can execute.
*Threads can also be suspended, leaving them in a stopped stated until continued. A thread can voluntarily preempt itself by yielding execution and explicitly block itself by sleeping.
*A thread usually exits at some point and, depending on the system, might enter an exited state where the thread waits to be joined or simply cease to exist.
Figure 18 – Thread states
A scheduling policy dictates how and when threads are to enter or leave the runnable, active, and blocked states. A scheduling policy defines:
*The criteria for selecting the next runnable thread to dispatch when an active thread yields or blocks.
*The conditions under which an active thread is to be preempted.
*The criteria for selecting the next thread to awaken if more than one thread is waiting on the same synchronization resource. In some cases, this determination is made by the synchronization mechanism and occurs regardless of scheduling policy.
The scheduling policy is system dependent. In some systems, each thread can be assigned a different scheduling policy, allowing the developer to choose the policy that best meets the requirements for that thread. In other systems, the scheduling policies are defined at the process level, or fixed according to a thread’s contention scope.
Possible scheduling policy values. The enumerated type, RWSchedulingPolicy, defines the set of all possible scheduling policy values supported by the Threading package as:
*RW_THR_OTHER — Included as a catch-all for scheduling policies that can’t be categorized as one of the policies defined by the remaining RWSchedulingPolicy values. This policy is usually mapped to the default policy of the underlying thread’s API, but is seldom returned by the getSchedulingPolicy() function, which generally returns the one of the policies (listed below) that most closely describes the default policy.
*RW_THR_PREEMPTIVE — In preemptive scheduling, threads run until preempted by a thread of higher-priority or until blocked. Thread priorities are set by the application; the system does not dynamically change a thread’s priority.
*RW_THR_TIME_SLICED_DYNAMIC — In systems with dynamic time-sliced scheduling, threads still run either until they are preempted by a thread of higher priority, until some time-quantum has elapsed, or until blocked. The difference is that the priority and/or time-slice quantum assigned to a thread can be altered dynamically by the system to give some level of fairness and optimization.
*RW_THR_TIME_SLICED_FIXED — Under a fixed, time-sliced scheduling policy, threads are still time-sliced, but the thread priorities are not altered by the system.
Using the feature test macro. The feature test macro for scheduling policy is RW_THR_HAS_SCHEDULING_POLICY. If this macro is not defined, attempts to query or set the scheduling policy attribute always produce an exception. If it is defined, then the current environment has some level of support or recognition for scheduling policy and might allow you to get or set the scheduling policy attribute.
Member functions. The RWThreadAttribute member functions that manipulate the scheduling policy attribute include:
*canGetSchedulingPolicy() — Indicates whether the scheduling policy attribute is supported in the current environment and whether getSchedulingPolicy() can currently return a legal value.
*isSchedulingPolicySet() — Indicates whether the scheduling policy attribute value is the value that was previously set by a call to setSchedulingPolicy(RWSchedulingPolicy).
*getSchedulingPolicy() — Returns the default scheduling policy value if the attribute value has not yet been defined. Otherwise, it returns the value specified in the last call to setSchedulingPolicy(RWSchedulingPolicy). If the current environment does not support or define the scheduling policy attribute, then attempts to use this function result in exceptions.
*canSetSchedulingPolicy() — Indicates whether the scheduling policy attribute and attribute value passed as an argument are supported in the current environment.
*setSchedulingPolicy(RWSchedulingPolicy) — Sets the scheduling policy attribute to the value passed as an argument. If the current environment does not support the scheduling policy attribute or the specified attribute value, then attempts to use this function result in exceptions.
*resetSchedulingPolicy() — Restores the scheduling policy attribute to its default value. The default value can vary according to the current value of other attributes.
Changing the contention scope. In addition to any environment-specific restrictions, the availability of individual scheduling policies often depends on the current contention scope. Changing the contention scope attribute value can cause a previous scheduling policy setting to be discarded and can affect the availability of specific scheduling policies.
Changing the scheduling policy. Similarly, changing the scheduling policy value can cause a previous setting of the priority and time-slice quantum attributes to be discarded. When you change the scheduling policy attribute, the Threading package validates these related attributes to insure that any previous setting is compatible with the new policy, and if not, resets that attribute. The default value and supported range for these dependent attributes often vary in response to changes in the scheduling policy value. The specific dependencies and validation requirements are unique to each environment.
Inheriting a scheduling policy. Scheduling policy can be inherited from the creating thread if the inheritance policy attribute is defined as RW_THR_INHERIT. If the inheritance attribute is RW_THR_EXPLICIT, the Threading package chooses a default policy appropriate for the current settings and environment.
Setting the scheduling policy. Setting the scheduling policy attribute value when the current inheritance policy is RW_THR_INHERIT forces the inheritance policy attribute to be changed to RW_THR_EXPLICIT.
Using the scheduling policy. The scheduling policy specified by an RWThreadAttribute can only be used when the thread is created. To manipulate the scheduling policy for an active thread, use the following RWThread and RWThreadSelf member functions:
*canGetSchedulingPolicy()
*getSchedulingPolicy()
*canSetSchedulingPolicy()
*setSchedulingPolicy(RWSchedulingPolicy)
Exceptions. In addition to throwing the same exceptions as their RWThreadAttribute counterparts, an RWTHRThreadNotActive exception is thrown if you attempt to query or set the scheduling policy on a threaded runnable that does not possess an active thread.