Reentrancy (computing)
Reentrancy is a programming concept where a function or subroutine can be interrupted and then resumed before it finishes executing. This means that the function can be called again before it completes its previous execution. Reentrant code is designed to be safe and predictable when multiple instances of the same function are called simultaneously or in quick succession. A computer program or subroutine is called reentrant if multiple invocations can safely run concurrently on multiple processors, or if on a single-processor system its execution can be interrupted and a new execution of it can be safely started (it can be "re-entered"). The interruption could be caused by an internal action such as a jump or call, or by an external action such as an interrupt or signal, unlike recursion where new invocations can only be caused by internal call. This definition originates from multiprogramming environments, where multiple processes may be active concurrently and where the flow of control could be interrupted by an interrupt and transferred to an interrupt service routine (ISR) or "handler" subroutine. Any subroutine used by the handler that could potentially have been executing when the interrupt was triggered should be reentrant. Similarly, code shared by two processors accessing shared data should be reentrant. Often, subroutines accessible via the operating system kernel are not reentrant. Hence, interrupt service routines are limited in the actions they can perform; for instance, they are usually restricted from accessing the file system and sometimes even from allocating memory. Reentrancy is neither necessary nor sufficient for thread-safety in multi-threaded environments. In other words, a reentrant subroutine can be thread-safe,[1] but is not guaranteed to be[citation needed]. Conversely, thread-safe code need not be reentrant (see below for examples). Other terms used for reentrant programs include "sharable code".[2] Reentrant subroutines are sometimes marked in reference material as being "signal safe".[3] Reentrant programs are often[a] "pure procedures". BackgroundReentrancy is not the same thing as idempotence, in which the function may be called more than once yet generate exactly the same output as if it had only been called once. Generally speaking, a function produces output data based on some input data (though both are optional, in general). Shared data could be accessed by any function at any time. If data can be changed by any function (and none keep track of those changes), there is no guarantee to those that share a datum that that datum is the same as at any time before. Data has a characteristic called scope, which describes where in a program the data may be used. Data scope is either global (outside the scope of any function and with an indefinite extent) or local (created each time a function is called and destroyed upon exit). Local data is not shared by any routines, re-entering or not; therefore, it does not affect re-entrance. Global data is defined outside functions and can be accessed by more than one function, either in the form of global variables (data shared between all functions), or as static variables (data shared by all invocations of the same function). In object-oriented programming, global data is defined in the scope of a class and can be private, making it accessible only to functions of that class. There is also the concept of instance variables, where a class variable is bound to a class instance. For these reasons, in object-oriented programming, this distinction is usually reserved for the data accessible outside of the class (public), and for the data independent of class instances (static). Reentrancy is distinct from, but closely related to, thread-safety. A function can be thread-safe and still not reentrant. For example, a function could be wrapped all around with a mutex (which avoids problems in multithreading environments), but, if that function were used in an interrupt service routine, it could starve waiting for the first execution to release the mutex. The key for avoiding confusion is that reentrant refers to only one thread executing. It is a concept from the time when no multitasking operating systems existed. Rules for reentrancy
Reentrancy of a subroutine that operates on operating-system resources or non-local data depends on the atomicity of the respective operations. For example, if the subroutine modifies a 64-bit global variable on a 32-bit machine, the operation may be split into two 32-bit operations, and thus, if the subroutine is interrupted while executing, and called again from the interrupt handler, the global variable may be in a state where only 32 bits have been updated. The programming language might provide atomicity guarantees for interruption caused by an internal action such as a jump or call. Then the function ExamplesTo illustrate reentrancy, this article uses as an example a C utility function, Neither reentrant nor thread-safeThis is an example swap function that fails to be reentrant or thread-safe. Since the int tmp;
void swap(int* x, int* y)
{
tmp = *x;
*x = *y;
/* Hardware interrupt might invoke isr() here. */
*y = tmp;
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
Thread-safe but not reentrantThe function _Thread_local int tmp;
void swap(int* x, int* y)
{
tmp = *x;
*x = *y;
/* Hardware interrupt might invoke isr() here. */
*y = tmp;
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
Reentrant and thread-safeAn implementation of void swap(int* x, int* y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp; /* Hardware interrupt might invoke isr() here. */
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
Reentrant interrupt handlerA reentrant interrupt handler is an interrupt handler that re-enables interrupts early in the interrupt handler. This may reduce interrupt latency.[6] In general, while programming interrupt service routines, it is recommended to re-enable interrupts as soon as possible in the interrupt handler. This practice helps to avoid losing interrupts.[7] Further examplesIn the following code, neither int v = 1;
int f()
{
v += 2;
return v;
}
int g()
{
return f() + 2;
}
In the above, These slightly altered versions are reentrant: int f(int i)
{
return i + 2;
}
int g(int i)
{
return f(i) + 2;
}
In the following, the function is thread-safe, but not (necessarily) reentrant: int function()
{
mutex_lock();
// ...
// function body
// ...
mutex_unlock();
}
In the above, NotesSee alsoReferences
Works cited
Further reading
|
Portal di Ensiklopedia Dunia