Only possible drawback is that they might perform worse than the alternative, at least in some cases.
Only possible drawback is that they might perform worse than the alternative, at least in some cases.
Seems very closely related to condition variables - except you specify the condition at the lock site rather than via a “trigger” before an unlock. I think Google’s internal Mutex class had a LockWhen(callback) which is a pleasure to work with. Definitely an awesome concept.
To understand it better here's the solution to the producer/consumer problem (from wikipedia), using mutexes and semaphores:
mtx buffer_mutex;
sem fillCount = 0;
sem emptyCount = BUFFER_SIZE;
procedure producer()
{
while (true)
{
item = produceItem();
down(emptyCount);
down(buffer_mutex);
putItemIntoBuffer(item);
up(buffer_mutex);
up(fillCount);
}
}
procedure consumer()
{
while (true)
{
down(fillCount);
down(buffer_mutex);
item = removeItemFromBuffer();
up(buffer_mutex);
up(emptyCount);
consumeItem(item);
}
}
and the same problem solved using CCRs: int avl = 0;
procedure producer()
{
while (true)
{
item = produceItem();
region R when (avl < BUFFER_SIZE)
{
putItemIntoBuffer(item);
avl++;
}
}
}
procedure consumer()
{
while (true)
{
region R when (avl > 0)
{
item = removeItemFromBuffer();
avl--;
}
consumeItem(item);
}
}
The most important thing about CCRs is that they are supposed to guarantee fairness, along with mutual exclusion. A well-designed solution uses two binary semaphore queues to achieve this.If anyone wants to see what an implementation looks like here's a small C library I wrote a while ago, to use for some of my own personal projects, and to solve some homework for Uni https://github.com/Gikoskos/libccr
Yes, entry barriers: http://www.ada-auth.org/standards/12rm/html/RM-9-5-2.html#S0...
The consumer/producer routines (entries) conceptually belong to the object/resource that is operated on (protected object) but are executed by the calling task.
Below is an Actor implementation of a read priority solution to the readers writers problem:
ReadPriority[aDatabase:*ReadersWriter*]:*ReadersWriterManager*
// Invariant: **Nonempty** #writing# ⇨ **IsEmpty** #reading#
**Locals**(Queue(#writersQ#, #readersQ#),
Crowd(#reading#),
AtMostOne(#writing#)),
**Handlers**(
⟦scheduler⟧ ↦ **As** myScheduler, // myScheduler facet of this manager
upgrade[newVersion] ↦
(**CancellAll** #readersQ# **and** #writersQ# **and** #reading# **and** #writing#
**for** **Become** newVersion)
myScheduler **implements** *ReadersWriter* **Handlers**(
read[aQuery] ↦
**Enqueue** #readersQ# **when** **Nonempty** #writing# **or** #writersQ# **or** #readersQ#
**for** aDatabase.read[aQuery] **thru** #reading#
**permit** #readersQ#
**afterward** **Permit** #writersQ# **when** **IsEmpty** #reading#
**else** #readersQ# **when** **IsEmpty** #writersQ#,
write[anUpdate] ↦
**Enqueue** #writersQ# **when** **Nonempty** #reading# **or** #readersQ# **or** #writing# **or** #writersQ#
**for** aDatabase.write[anUpdate] **thru** #writing#
**afterward** **Permit** #readersQ# **else** #writersQ#)▮