I am trying to explain only 1 problem which shows the basic loophole in this approach.
Assume that you are supporting only insert operation for now and not any other operations. Following could be an implementation for the insert operation:
//Using C
BSTNode* insert(BSTNode* root,int value)
{
1 if(root == NULL){
2 return createNewNode(value);
3 }
4
5 if(root->data == value){
6 return root;
7 }
8 else if(root->data > value){
9 while(root->leftLock);
10 if(!root->left){
11 root->leftLock = true;
12 root->left = insert(root->left,value);
13 root->leftLock = false;
14 }
15 else{
16 root->left = insert(root->left,value);
17 }
18 }
19 else{
20 while(root->rightLock);
21 if(!root->right){
22 root->rightLock = true;
23 root->right = insert(root->right,value);
24 root->rightLock = false;
25 }
26 else{
27 root->right = insert(root->right,value);
28 }
29 }
30
31 return root;
32
}
In this approach, since only the children of the last node (leaf node) will get updated upon inserting a value, So we are not doing any locking while updating the parents (when recurring back).
I am avoiding insertion request queuing and using spinlocks only to keep it a little simple. However the point i am gonna raise will be same for that case too...
Consider this BST:
10
/ \
5 15
/ \ / \
2 6 13 20
Suppose 2 threads t1 and t2 are invoked simultaneously trying to insert values 25 and 26 respectively and currently are at BSTNode with value 20.
(The rightmost node).
Now lets execute the above code with context switching between the threads:
a. t1:
1. if(root == NULL) //not true, will go to line 5.
//switch
b. t2:
1. if(root == NULL) //not true, will go to line 5.
//switch
c. t1:
5. if(root->data == value){ //not true, will go to line 8.
8. else if(root->data > value) //not true, will go to line 19.
//switch
d. t2:
5. if(root->data == value){ //not true, will go to line 8.
//switch
e. t1:
19 else{
20 while(root->rightLock); // lock is not held by anyone, so continue.
21 if(!root->right){
//switch
f. t2:
8. else if(root->data > value) //not true, will go to line 19.
19 else{
20 while(root->rightLock); // lock is not helpd by anyone, so continue.
21 if(!root->right){
22 root->rightLock = true;
//switch
g. t1:
22 root->rightLock = true;
23 root->right = insert(root->right,value);
//switch
h. t2:
23 root->right = insert(root->right,value);
24 root->rightLock = false;
//switch
Assume that line 23 covers complete execution of that line.
As you can see in section f,g and h that both t1 and t2 are entering into critical section without knowing the presence of each other. The code was not supposed to allow that.
Whats the problem then ???
The problem is that there is a piece of code which was supposed to be executed in one go:
20 while(root->rightLock);
21 if(!root->right){
22 root->rightLock = true;
So we may need some hardware control by making our own uninterruptible instruction which executes all 3 tasks mentioned above together.