Why is the following snippet for deleting a node in a linked list not thread safe?
edit: note every node has a lock of its own
// ... lock acquisitio
It is thread safe assuming the scope of your lock (meaning what it locks, nothing to do with the official term "scope" used in C) is large enough.
If it locks just the current node p
, then you can't rely on other threads not coming in and playing with prev
(or head
or tail
for that matter) and hence under-cutting you.
If it locks the entire structure, then yes, it is thread-safe.
We can't tell the scope of your lock from the code given but I will mention one other (unrelated) thing.
You should probably either free p
or add it to a free list for re-use. Simply setting its next
pointer to null and its deleted
flag to 1 won't let you find it when you need to reuse it. That will lead to a memory leak. It may be that the code to do this just isn't shown but I thought I'd mention it, just in case.
Based on your edit where you state you're using a fine-grained approach (one lock per node):
Provided you lock all three of the "nodes" that you're using or changing, and that you lock them in a consistent direction, it's still thread-safe.
I put "nodes" in quotes since it also applies to the head
and tail
pointers. For example, if you want to delete the first node in a ten-node list, you need to lock the head
variable and the first and second nodes, in that order. To delete the last node in a one-node list, you need to lock both the head
and tail
variables and the node.
Locking of all three "nodes" will prevent threads from adversely affecting each other.
Locking them in a consistent direction (such as from head
towards tail
) will prevent deadlocks.
But you have to lock all three before attempting to change anything.
This will even prevent it from concurrent insert operations provided the insert locks the two "nodes" on either side of the insertion point and, of course, locks them in the same direction.
Not sure how well iterating over the list would go though. You could probably get away with a system whereby you initially lock the head
variable and the first node, then release head
.
Then, when you've finished with that node, lock the next one before releasing the current one. That way, you should be able to iterate through the list without being affected by inserts or deletes, which can only happen in areas you're not currently working with.
But, the bottom line is that you can certainly make it thread safe, even with a fine-grained locking scope.