I have been asked to implement a lock free queue in c using compare and exchange, however my knowledge of pointers is fairly limited.
I have been using the following code to test my (as yet incomplete) dequeue implementation, but I believe it is looping infinitely because I’m not terribly sure how to properly use pointers/address of operator.
I have been given this CAS function to use, since I know nothing of assembler.
long __cdecl compare_exchange(long *flag, long oldvalue, long newvalue)
{
__asm
{
mov ecx, flag
mov eax, oldvalue
mov ebx, newvalue
lock cmpxchg [ecx], ebx
jz iftrue
}
return 0;
iftrue: return 1;
}
My current (relevant) code is as follows…
typedef struct QueueItem
{
int data;
struct QueueItem* next;
}item;
struct Queue
{
item *head;
item *tail;
}*queue;
int Dequeue()
{
item *head;
do
{
head = queue->head;
if(head == NULL)
return NULL_ITEM;
printf("%d, %d, %d\n", (long *)queue->head, (long)&head, (long)&head->next);
}
while(!compare_exchange((long *)queue->head, (long)&head, (long)&head->next)); // Infinite loop.
return head->data;
}
int main(int argc, char *argv[])
{
item i, j;
queue = (struct Queue *) malloc(sizeof(struct Queue));
// Manually enqueue some data for testing dequeue.
i.data = 5;
j.data = 10;
i.next = &j;
j.next = NULL;
queue->head = &i;
printf("Dequeued: %d\n", Dequeue());
printf("Dequeued: %d\n", Dequeue());
}
Should I be using the not operator inside of the do while loop? If I don’t use that operator, I get an output of “Dequeued 5” x2, which suggests the swap isn’t happening and that I should use the not. If so, where am I going wrong? I’d put money on it being a pointer/address operator issue.
There is confusion on the pointers and values. Here is corrected code:
You were trying to write what queue->head was pointing to, not the value of queue->head itself.
In addition, to make it work properly on multicore, I believe you need to define the head as volatile.