Overview | Group | Tree | Graph | Index | Concepts |
Description |
Writing Multi-Threaded Applications |
Limitations |
Managing the Initial Requirement Amount on a Durable Resource |
Scheduler Engine offers an easy way to build applications where the same resources are used successively in different scheduling problems and information about resource availability is kept from one problem to another. Such resources are called durable resources. The information about resource availability that is kept from one problem to another is stored in the timetable constraints of the resources.
The typical steps that may be encountered by an application using durability are:
IlcSchedule
. The durable
scheduler can be seen as an object that stores the information that is kept from one problem to another (timetables of durable resources).IlcSchedule
), called
computation schedules, declare an interest in using some durable resources.Example
The main elements of the API that allow the use of durable resources across different scheduling problems are illustrated in the following example.
The following code creates a durable schedule that gets its durable resources extracted from a Scheduler model.
IloEnv env0; // Allocation environment IloModel model0(env0); IloUnaryResource resource(env0); model0.add(resource); IloSolver solver0(env0); IlcScheduler durSched(solver0); durSched.setDurable(); // A durable schedule is created solver0.extract(model0); // Extract durable resources durSched.close(); // All durable resources were defined
Now we define a goal
SolveSubProblem
, which is in
charge of scheduling one activity on the durable unary resource. In the goal “wrapper,” the computation resource is obtained from the durable scheduler.
ILCGOAL1(SolveSubProblemIlc, IlcUnaryResource, compResource) { IloSolver solver = getSolver(); IlcSchedule compSched(solver, 0, 24); // computation schedule IlcActivity act(compSched, 8); compSched.lock(1, compResource); // Locking before using solver.add(act.requires(compResource)); solver.startsNewSearch(IlcSetTimes(compSched)); solver.next(); compSched.unlock(1, compResource); // Resource no longer needed solver.out() << act << endl; // Display scheduled activity solver.endSearch(); return 0; } ILOCPGOALWRAPPER2(SolveSubProblem, solver, IlcScheduler, durSched, IloUnaryResource, resource) { return SolveSubProblem(solver, durSched.getUnaryResource(resource)); }
The following code creates a computation solver to solve a first instance of
sub-problem
on the durable resource.
IloEnv env1; // Computation environment IloSolver solver1(env1); solver1.solve (SolveSubProblem(env1, solver1, compResource)); env1.end();
It outputs:
[0
--
8
-->
8]
. The activity of this first sub-problem is scheduled to start at time 0. From now on, the durable resource remains occupied on the time interval [0, 8). Thus a second computation solver trying to place another activity on the resource will be aware of the resource availability:
IloEnv env2; // Computation environment IloSolver solver2(env2); solver2.solve (SolveSubProblem(env2, solver2, compResource)); env2.end();
It outputs:
[8
--
8
-->
16]
. The activity of the second
sub-problem
is scheduled to start at time 8.
It is possible to use durable resources in multi-threaded applications. Scheduler is multi-thread safe if each thread uses a different solver for creating scheduler objects and those objects are not accessed across different threads.
Durable resources may be concurrently used by different threads through the methods
lock
and
unlock.
lock
method may block while waiting for all arguments to be unlocked by other threads.
unlock
ethod allows other threads to gain access to its arguments.Currently, the only resources that can be managed as durable resources are discrete and unary resources, and energy resources.
The durable resources are shared by several independent computational solvers. The whole set of requirements on a durable resource is not known. Also, the following limitations exist:
setCapacityMin
,
getCapacityMin
,
setEnergyMin
,
getEnergyMin
will not work reliably.When entering a new session using durable resources, or when a commitment from a previous search phase must be removed (to figure out a rollback on a database), one needs specific functions for having non-monotonic, non- reversible behavior. Those functions are:
void IlcCapResource::incrDurableRequirement (IlcInt t1, IlcInt t2, IlcInt capacity, IlcInt outward = IlcTrue, IlcInt breaksDuration = 0); void IlcCapResource::incrDurableRequirement (IlcIntToIntStepFunction func);
These functions modify the requirement amount that corresponds to an activity starting a
t1
, ending at
t2
and requiring the capacity of the argument
capacity
. The signature of this function, using an instance of
IlcIntToIntStepFunction
,
nearly behaves like the iteration of the basic signature on each step of the function.
If the argument
capacity
is greater than 0, the effect of the function is to add
capacity
to the requirement amount to the resource; that is, to actually decrease the available capacity in the resource.
If the argument
capacity
is less than 0, the effect of the function is to remove
capacity
from the requirement amount of the resource; that is, to increase the available capacity in the resource.
The coherency of the requirement amount with respect to the resource capacity is under the responsibility of the user. For example, one should be cautious that the requirements that are undone do not exceed the activity requirements that are committed on the resource when a search using the durable resource is launched.
For a multi-threaded durable resource, these functions are enclosed in a critical section. That is, these functions are MT-hot.
In addition to the limitations described in the previous paragraph, the durable schedule be must closed and the resource must not be involved in a computational solver.
See Also