Ada
programming
concurrency
entry mechanism
fire and forget

Fire and forget entry/accept mechanism in Ada

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Ada has strong built-in support for concurrency, but its entry and accept model is based on rendezvous, not a true fire-and-forget call. If the caller must continue immediately, the usual solution is to queue work through a protected object and let a worker task process it later.

Why a normal entry call is not fire-and-forget

An Ada task entry is synchronous. The caller invokes an entry, then waits until the receiving task reaches a matching accept statement. That synchronization is useful when both sides need a handshake, but it means the caller does not simply dispatch work and continue.

A simplified task declaration looks like this:

ada
task Worker is
   entry Process (Value : Integer);
end Worker;

And the body performs the rendezvous:

ada
1task body Worker is
2begin
3   loop
4      accept Process (Value : Integer) do
5         null;
6      end Process;
7   end loop;
8end Worker;

A caller that executes Worker.Process(42); blocks until the accept happens. That is coordinated task communication, not fire-and-forget behavior.

A non-blocking pattern that behaves like fire-and-forget

If you want the caller to enqueue work and return immediately, use a protected object as the handoff point. The protected procedure returns quickly, while a separate worker task consumes queued items.

ada
1with Ada.Text_IO; use Ada.Text_IO;
2
3procedure Main is
4
5   protected type Job_Queue is
6      procedure Enqueue (Item : in Integer);
7      entry Dequeue (Item : out Integer);
8   private
9      Buffer   : Integer := 0;
10      Has_Item : Boolean := False;
11   end Job_Queue;
12
13   protected body Job_Queue is
14      procedure Enqueue (Item : in Integer) is
15      begin
16         Buffer := Item;
17         Has_Item := True;
18      end Enqueue;
19
20      entry Dequeue (Item : out Integer) when Has_Item is
21      begin
22         Item := Buffer;
23         Has_Item := False;
24      end Dequeue;
25   end Job_Queue;
26
27   Queue : Job_Queue;
28
29   task Worker;
30
31   task body Worker is
32      Value : Integer;
33   begin
34      loop
35         Queue.Dequeue (Value);
36         Put_Line ("Processing" & Integer'Image (Value));
37      end loop;
38   end Worker;
39
40begin
41   Queue.Enqueue (42);
42   Put_Line ("Caller continues immediately");
43end Main;

The call to Queue.Enqueue(42) is the fire-and-forget part. The caller returns immediately after storing the work item. The worker task handles the job asynchronously.

Why protected objects are a better fit

Protected objects are designed for safe, efficient shared-state coordination. They are often a better match than task entries when the sender does not need an immediate response.

This design also separates concerns cleanly:

  • The caller only submits work.
  • The queue controls synchronization.
  • The worker owns the processing logic.

In real applications, the queue would usually store multiple items instead of a single slot, but the pattern stays the same.

Alternatives and design choices

If the sender needs confirmation, use an entry call or another explicit synchronization mechanism. If the sender only needs to notify another part of the program, a protected procedure plus worker task is simpler and more honest about the behavior.

Ada also supports selective waits and timed entry calls, which are useful when you want bounded waiting. Those are still rendezvous-based and do not change the fact that a direct entry call is synchronized.

Common Pitfalls

The biggest pitfall is assuming entry means asynchronous message passing. It does not. A normal entry call participates in a rendezvous and therefore blocks until the receiving task accepts it.

Another problem is putting long-running work inside a protected operation. Protected procedures should stay short. Use them to update shared state or queue work, then let a task do the heavy processing.

A single-slot queue like the one above is only a teaching example. Real systems need a bounded buffer, overwrite policy, or back-pressure strategy so fast producers do not lose data.

Finally, think about shutdown. Infinite worker loops are common in examples, but production code usually needs a sentinel message or a controlled termination path.

Summary

  • Ada entry and accept are synchronous rendezvous operations.
  • A direct entry call is not true fire-and-forget behavior.
  • To get non-blocking submission, queue the work in a protected object and process it in a separate task.
  • Keep protected operations short and move long-running work into worker tasks.
  • Pick the pattern based on whether the caller needs synchronization or only one-way notification.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.