Ticket (Concurrency)

A ticket is a handle the client receives immediately when submitting work, which they later redeem to obtain the result. Like dropping off dry cleaning: you get a numbered stub, come back later, exchange it for the finished item. In uC++ this is the building block under futures.

Why a ticket instead of just having the server return a result?

Because a normal mutex call blocks the caller for the full service time. A ticket lets the caller issue the request, keep working, and block only when they actually need the answer, shifting the wait from “now” to “when I’m ready.” It’s the essence of asynchronous programming: trade a synchronous call for (handle, redeem) pairs.

Two-call protocol (Buhr §9.3.2.1)

A server call that returns a result is split into start( arg ) / wait(). The server keeps a table of pending work keyed by the ticket; wait blocks or polls until that slot is filled.

_Task Server {
    struct Slot { int arg; int result; bool ready; };
    Slot slots[MAX];
  public:
    int start( int arg ) {                   // first call: returns ticket
        int id = allocSlot();
        slots[id] = { arg, 0, false };
        return id;
    }
    int wait( int id ) {                     // second call: returns result
        while ( ! slots[id].ready ) _Accept( ready );
        freeSlot( id );
        return slots[id].result;
    }
  private:
    void main() {
        for ( ;; ) {
            _Accept( start );
            _Accept( wait );
            // between accepts, process pending slots, then _Accept(ready)
        }
    }
};
 
int t = server.start( 42 );
// ... caller does unrelated work ...
int ans = server.wait( t );

Pitfalls (Buhr)

  • Protocol violations: caller never redeems ⇒ slot leaks; uses same ticket twice ⇒ double-free; forges a ticket ⇒ reads garbage or another client’s result
  • Poll vs block: wait() either blocks when the result is unready (cheap if the caller is idle) or returns a sentinel so the caller can loop (cheap if the caller has other work)
  • Ticket reuse requires matching allocation strategy (stack-of-free-ids or generation counter to detect stale tickets)

Relationship to futures

A future is a ticket with a richer API (callbacks, exceptions, chaining). See uFuture for the uC++ Future_ISM / Future_ESM implementation.

Pitfalls

  • Lost tickets leak slots ⇒ server must age them out or require redemption.
  • Double-redeem must be idempotent or rejected.
  • Server death invalidates outstanding tickets, redeemers need exception path.