1. A method comprising: exposing at least one function of a first application programming interface that, when invoked by a first thread of a process, receives from the first thread as parameters a target memory address and a current value observed by the first thread at the target memory address; checking, in response to the first application programming interface being invoked, whether the target memory address still has the current value observed by the first thread at the target memory address; in response to the target memory address not still having the current value observed by the first thread at the target memory address, returning to the first thread an indication to recheck the value at the target memory address; in response to the target memory address still having the current value observed by the first thread at the target memory address: maintaining a record of the first thread and the target memory address, allowing the first thread to be identified in response to a value at the target memory address being subsequently modified, and putting the first thread to sleep; and exposing at least one function of a second application programming interface that, when invoked by a second thread to indicate that a value at a memory address has been modified, receives from the second thread as a parameter of the second application programming interface the memory address that has been modified; checking whether the memory address received from the second thread matches the target memory address; and waking up the first thread in response to the memory address received from the second thread matches the target memory address.