With pthreads, standard way is to use a mutex and use a condition variable for waiting in one thread until woken up by another.
Pseudocode, where writer will block briefly but never for indeterminate time, and buffer overflow is handled by throwing away unread data:
Writer write:
acquire new data to write
lock mutex
get current writing position in buffer
compare to current reading position and check for overflow
in case of overflow, update reading position (oldest data lost)
write new data to buffer
update writing position
do wakeup on condition variable
unlock mutex
Reader read:
lock mutex
loop:
get current reading position in buffer
compare to current writing position in buffer
if there's new data, break loop
wait (possibly with timeout) on condition variable
goto loop:
copy data from buffer
update reading position
unlock mutex
process copied data
Obviously above, writer may briefly block on mutex, but because reader will hold the mutex only briefly (this assumes data in buffer is fairly short), this is probably not a problem.
Important details about understanding above code: condition variable and mutex work as a pair. Waiting on condition variable will unlock the mutex, and once waken up, will continue only after it can re-lock the mutex. So reader will not actually continue until writer unlocks the mutex.
It's important to check buffer positions again when condition variable wait returns, and not blindly trust that wakeup was done by writer which just put more data to it.