I can think of three methods using only threading primitives:
Triple mutex
Three mutexes would work here:
- data mutex (‘M’)
- next-to-access mutex (‘N’), and
- low-priority access mutex (‘L’)
Access patterns are:
- Low-priority threads: lock L, lock N, lock M, unlock N, { do stuff }, unlock M, unlock L
- High-priority thread: lock N, lock M, unlock N, { do stuff }, unlock M
That way the access to the data is protected, and the high-priority thread can get ahead of the low-priority threads in access to it.
Mutex, condition variable, atomic flag
The primitive way to do this is with a condition variable and an atomic:
- Mutex M;
- Condvar C;
- atomic bool hpt_waiting;
Data access patterns:
- Low-priority thread: lock M, while (hpt_waiting) wait C on M, { do stuff }, broadcast C, unlock M
- High-priority thread: hpt_waiting := true, lock M, hpt_waiting := false, { do stuff }, broadcast C, unlock M
Mutex, condition variable, two non-atomic flag
Alternatively you can use two non-atomic bools with a condvar; in this technique the mutex/condvar protects the flags, and the data is protected not by a mutex but by a flag:
-
Mutex M;
-
Condvar C;
-
bool data_held, hpt_waiting;
-
Low-priority thread: lock M, while (hpt_waiting or data_held) wait C on M, data_held := true, unlock M, { do stuff }, lock M, data_held := false, broadcast C, unlock M
-
High-priority thread: lock M, hpt_waiting := true, while (data_held) wait C on M, data_held := true, unlock M, { do stuff }, lock M, data_held := false, hpt_waiting := false, broadcast C, unlock M