ZHIFAN YIN
ZHIFAN YIN

Reputation: 13

Does WaitOnAddress return when values match or when values differ?

I am trying to use the WaitOnAddress() function to achieve read-write synchronization.

According to MSDN, WaitOnAddress() has the following declaration:

BOOL WaitOnAddress(
  volatile VOID *Address,
  PVOID         CompareAddress,
  SIZE_T        AddressSize,
  DWORD         dwMilliseconds
);

and the following parameter definition:

CompareAddress

A pointer to the location of the previously observed value at Address. The function returns when the value at Address differs from the value at CompareAddress.

According to the definition, I should store and pass the current value of the watched address, so when the watch value changes, WaitOnAddress() will return. But this function does not work as I expected, so I wrote the following test code for WaitOnAddress() in Visual Studio (and also included linker library Synchronization.lib):

#include <stdio.h> 
#include <stdlib.h>  // atoi 
#include <string.h> 

// include these two files after including winsock2.h
#include <process.h>
#include <Windows.h>
#include <synchapi.h>

void* threads(void* num) {
    int* number = (int*)num;
    for (int i = 0; i < 10; i++) {
        printf("number = %d\n", *number);
    }
    int catch = *number; // will be passed as CompareAddress
    WaitOnAddress((int*)num, &catch, sizeof(int), INFINITE);
    for (int i = 0; i < 10; i++) {
        printf("number2 = %d, %d\n", catch, *(int*)num);
    }
    return NULL;
}

int main() {
    int int_list[10];
    for (int i = 0; i < 10; i++) {
        int_list[i] = i;
        _beginthread(threads, 0, (void*)&int_list[i]);
    }
    printf("hello\n");
    Sleep(1000);
    for (int i = 0; i < 10; i++) {
        int_list[i] = 10 - i;
    }
    printf("changed\n");
    Sleep(1000);
    return 0;
}

In above code, WaitOnAddress() never returns even though the value it watches changes. But, if I change

int catch = *number;

to:

int catch = 10 - *number;

then WaitOnAddress() returns and the rest of the output is printed, as if it returns ONLY when the watched value matches the compared value.

But, I want to used the described behavior so my thread is released whenever the watched variable is changed.

Upvotes: 0

Views: 205

Answers (1)

Zeus
Zeus

Reputation: 3890

According to the documentation:

Parameters

Address

The address on which to wait. If the value at Address differs from the value at CompareAddress, the function returns immediately. If the values are the same, the function does not return until another thread in the same process signals that the value at Address has changed by calling WakeByAddressSingle or WakeByAddressAll or the timeout elapses, whichever comes first.

Although you modify the value of the original array in the second loop, the catch and num are always the same when calling WaitOnAddress in the thread, so the WaitOnAddress function will not return.

You can try to modify it to:

#include <stdio.h> 
#include <stdlib.h>  // atoi 
#include <string.h> 

// include these two files after including winsock2.h
#include <process.h>
#include <Windows.h>

void* threads(void* num) {
    int* number = (int*)num;
    printf("number = %d\n", *number);
    int catch = *number; // will be passed as CompareAddress
    WaitOnAddress((int*)num, &catch, sizeof(int), INFINITE);
    printf("number2 = %d, %d\n", catch, *(int*)num);
    return NULL;
}

int main() {
    int int_list[10];
    for (int i = 0; i < 10; i++) {
        int_list[i] = i;
        _beginthread(threads, 0, (void*)&int_list[i]);
    }
    printf("hello\n");
    Sleep(1000);
    printf("changed\n");
    for (int i = 0; i < 10; i++) {
        int_list[i] = 10 - i;
        WakeByAddressSingle(&int_list[i]);
    }
    Sleep(1000);
    return 0;
}

And it works for me:

enter image description here

Upvotes: 2

Related Questions