You have to use a blocking construct on a per-request basis.
This is called Futures (programming)
Each request will have its own Future. Once the request processing is started (possibly in a separate pool of threads, as you have described), the caller will be blocked on the Future's fulfillment, or failure.
When the result arrives, the Future is unblocked, and the call will return to the application.
When using this pattern, one must take great care prevent deadlocks and zombies. In other words, the Future needs to be unblocked at some time, whether the result is successful or failure (and in case of failure, throwing an exception back to the application is a fair game) - the call must not just hang there indefinitely.
As to thread-pool design:
- There will be at least one thread per simultaneous requester (i.e. application), which will be blocked during the request.
- If the applications and the service are inside the same process, these threads are the same as the application threads, which will become blocked.
- There will be a separate thread pool, requiring as many threads as is necessary to do the work between the service and the internet. These threads are in addition to the request-accepting threads.
- The exact number depends on how the work is done. It is possible to use asynchronous pattern (reactor) here, which might reduce the number of threads needed, but that will not have any effect on the number of request-accepting threads.
If the request from Application to Service occurs over network, there is a decoupling between Application threads and Service threads (in other words, a blocking of an Application request does not involve a "thread" at all; just a non-response from a network connection.) In that case the Service can also use reactor pattern, which means you can further reduce the number of threads.
In .net the async await
keywords are an extension of the Task Parallel Library. When you do not await
an async
method it is almost equivalent to calling Task.Run(()=>A())
(There are some gotchas regarding UI threads or other single threaded applications here as with out .ConfigureAwait(false)
, when creating the task, the awaited code will try to pick up on the same thread context. If you are awaiting from a background worker thread context then await and Task.Run()
are running in the same context. If you are on the UI thread then the context of Task.Run()
and the awaited context are different.)
In your example A() would start, return control at await B()
and then the code calling A()
would continue while A()
was waiting for B()
to complete.
A simple example would be the following:
static void Main(string[] args)
{
Console.WriteLine("Starting main");
A();
Console.WriteLine("Finished Main");
//dont end before A() finishes.
Console.ReadLine();
}
static async Task A()
{
Console.WriteLine("starting A");
await B();
Console.WriteLine("Finishing a");
}
static async Task B()
{
//Add a delay before the Console.WriteLine
await Task.Delay(1000);
Console.WriteLine("starting B");
await Task.Delay(1000);
Console.WriteLine("Finishing b");
}
When the main method calls A()
execution is serial until the await B()
. After A()
calls await, control is returned to main which then finishes. At this point A()
is still out there running "Fire and Forget", which is bad in the case of a console program so we need to make sure that the main thread does not complete before A()
finishes. If we don't have the Console.ReadLine();
the program will end after the call to await
in A()
.
Best Answer
Are you aiming at making a general-purpose Javascript to C automatic translator (that is, a compiler from Javascript to C)?
This is quite challenging and will take you several years of work, in particular if you want to make an efficient Javascript to C compiler (something which won't be much slower than most current Javascript implementations)
Notice that semantically Javascript has a lot of common features with Scheme (dynamic typing, garbage collection, closures, and perhaps run-time evaluation), even if the syntax is very different. Its prototype object model is indeed not in Scheme, but you could find some implementations of prototype object models in Scheme quite similar to the Javascript model. So I definitely recommend studing Scheme and its formal semantics, and looking inside several Scheme to C translators (Bigloo, Chicken, Stalin, ...). In contrast to Scheme, Javascript was initially ill-defined (its first implementation was a few weeks hack!) and has some unpleasant peculiarities (result of
[] + {}
, etc...) that are painful to handle in a Javascript to C translator.Then I strongly recommend reading C.Queinnec Lisp In Small Pieces book. Read also Scott's programming language pragmatics book.
The asynchronous aspect of Javascript is similar to coroutines and to continuation passing style (a.k.a. CPS). Look into Continuation Passing C, it is translating a program in CPC (an extended dialect of C, with yield, spawn, wait, ... primitives usable for asynchronous computations) into plain C using continuation passing style techniques.
If your goal is not a general-purpose translator of Javascript to C, but simply to manually rewrite a specific Javascript program into C, coroutines, callbacks, closures, and CPS are still useful concepts to assess. And you could even generate or write code for CPC then use the CPC compiler to get ordinary C.
You might also implement your asynchronous computations using the deprecated setcontext(3) routine, but I don't recommend using that since it is deprecated, very low level (basically it is setting all the machine registers), somehow machine specific, and difficult to debug.
Of course you could also consider multi-threading, e.g. POSIX pthreads or C11 threads.