How race conditions will caused by context switching [closed]
I want to know how race condition will happen during context switching, and where and how this happens.
I know about race condition can occur when accessing shared resource, I just need to understand it better. Can someone help me grasp this?
Here's a classic example:
int global_int = 0;
void update () {
++ global_int;
/* generated assembly is something like
register = global_int
increment register
global_int = register
*/
}
Say the first thread starts running, calls update()
, but gets interrupted (by a signal, context switch, whatever) in-between the second and third instructions. At this stage global_int==0
and register==1
: it hasn't saved the result yet.
Now suppose a second thread runs update()
and completes, so global_int==1
. The first thread resumes and saves register
(which is 1) to global_int
, yielding no change.
In this situation, global_int==1
after two calls to update()
have completed. Anything which assumes that update()
updates global_int
will now be broken.
In general it is very hard to detect this problem by looking at code, you have to analyse the data and say to yourself "global_int
is being accessed by different threads, I'd better guard it with a mutex". If you try to get clever and worry about how the threads will access it so as to avoid the expense of a lock, you will probably get it wrong except in trivial cases.
Race conditions are a consequence of concurrent execution code which accesses a shared resource without proper mechanisms to ensure the consistency of that shared resource.
A race condition could occur during context switching if there is a bug in the implementation of the thread scheduler that causes the code used to perform the context switch to access a shared resource without providing proper consistency guarantees. There is nothing about the code that implements context-switching that makes it unable to contain race conditions.
Suppose you were on a single-processor machine with a scheduler that is basically performing time-slicing of the available processor's resources (i.e., we're on a really simple system). Then suppose you have a critical section of code, but you did not guard that critical section with a mutex or other synchronization primitive.
Assume thread A
is inside the critical section. When the time-slice for thread A
is up, the scheduler schedules another thread B
and stops thread A
. Thread B
then enters the critical section (since there was no guard), and modifies the values in shared memory in the critical section. When thread B's
time-slice is up, the OS schedules thread A
again which continues from the point it left off inside the critical section. The only problem now though is that the values thread A
is working with are not what they were when it was stopped for the context-switch ... they're completely different since they were modified by thread B
. Thus you have a race-condition.
精彩评论