Compare commits

..

1 commit

Author SHA1 Message Date
e9b4f8e389 mutex(fix): prevent race condition (part 2)
In addition to the previous commit, this commit makes threads need to
wait for the thread manager to say it took the mutex from them before
they can ask for it again.
2024-11-19 15:12:42 -08:00

View file

@ -18,10 +18,10 @@ typedef void *(*ThreadTask)(const struct thread_data &);
typedef void *(*PthreadFun)(void *arg); typedef void *(*PthreadFun)(void *arg);
struct thread_group { struct thread_group {
bool wants_mutex[NUM_THREADS] = {0}; // set by the thread bool wants_mutex[NUM_THREADS] = {0};
bool has_mutex[NUM_THREADS] = {0}; // set by us, read by thread bool has_mutex[NUM_THREADS] = {0};
bool can_ask_for_mutex[NUM_THREADS] = {1}; // set by us, read by thread bool manager_took_mutex[NUM_THREADS] = {0};
bool threads_finished[NUM_THREADS] = {0}; // set by thread bool threads_finished[NUM_THREADS] = {0};
ThreadTask task; ThreadTask task;
size_t total_threads; size_t total_threads;
void *data; void *data;
@ -31,7 +31,7 @@ struct thread_data {
size_t id; size_t id;
bool *wants_mutex; bool *wants_mutex;
const bool *has_mutex; const bool *has_mutex;
const bool *can_ask_for_mutex; const bool *manager_took_mutex;
bool *is_finished; bool *is_finished;
void *data; void *data;
}; };
@ -55,10 +55,8 @@ void *thread_task_increment(const struct thread_data &thread) {
// mutex // mutex
{ {
// wait for permission to ask for the mutex // tell the thread manager we want the mutex
while (!*thread.can_ask_for_mutex) while (!*thread.manager_took_mutex)
;
// say we want the mutex
(*thread.wants_mutex) = true; (*thread.wants_mutex) = true;
// block until we have the mutex // block until we have the mutex
while (!*thread.has_mutex) while (!*thread.has_mutex)
@ -105,8 +103,8 @@ void do_threading(struct thread_group threads) {
threads.total_threads * sizeof(*threads.threads_finished)); threads.total_threads * sizeof(*threads.threads_finished));
// at the start, we have the mutex and haven't given it // at the start, we have the mutex and haven't given it
memset(threads.can_ask_for_mutex, 1, memset(threads.manager_took_mutex, 1,
threads.total_threads * sizeof(*threads.can_ask_for_mutex)); threads.total_threads * sizeof(*threads.manager_took_mutex));
// create thread data // create thread data
for (size_t tid = 0; tid < threads.total_threads; ++tid) { for (size_t tid = 0; tid < threads.total_threads; ++tid) {
@ -114,7 +112,7 @@ void do_threading(struct thread_group threads) {
.id = tid, .id = tid,
.wants_mutex = &threads.wants_mutex[tid], .wants_mutex = &threads.wants_mutex[tid],
.has_mutex = &threads.has_mutex[tid], .has_mutex = &threads.has_mutex[tid],
.can_ask_for_mutex = &threads.can_ask_for_mutex[tid], .manager_took_mutex = &threads.manager_took_mutex[tid],
.is_finished = &threads.threads_finished[tid], .is_finished = &threads.threads_finished[tid],
.data = threads.data, .data = threads.data,
}; };
@ -154,9 +152,9 @@ void do_threading(struct thread_group threads) {
// take the mutex from the thread that has it // take the mutex from the thread that has it
threads.has_mutex[tid_has] = false; threads.has_mutex[tid_has] = false;
threads.can_ask_for_mutex[tid_has] = true; threads.manager_took_mutex[tid_has] = true;
// give the mutex to the thread that wants it // give the mutex to the thread that wants it
threads.can_ask_for_mutex[tid_wants] = false; threads.manager_took_mutex[tid_wants] = false;
threads.has_mutex[tid_wants] = true; threads.has_mutex[tid_wants] = true;
} }