Сигнализация асинхронного ожидания потока

Мне нужен код C для программы, в которой N потоков могут взаимодействовать друг с другом.

каждый идентификатор потока может ждать любой идентификатор потока, который ему нужен.

каждый идентификатор потока может сигнализировать, какой идентификатор потока ему нужен.

они могут ждать и сигнализировать друг другу несколько раз.

когда поток получает сигнал, это означает, что он может перестать ждать потока и что два потока синхронизированы, как барьер, но вместо этого реализованы с помощью мьютекса и условных переменных.

каждый поток, который ожидает, ожидает сигнала от определенного потока с идентификатором, называемым приятелем, и с правильными int:synch_point и int:group. Если они не совпадают, поток должен продолжать ждать, пока такой сигнал не будет получен.

void signal_and_wait_for_thread(thread_data_t *thread_data, int myid, int buddy, int sync_point, int stride) {
    // Lock myid mutex and update the shared data
    pthread_mutex_lock(&thread_data->mutexes[myid]);
    thread_data->sync_points[myid] = sync_point;
    thread_data->strides[myid] = stride;
    //thread_data->ready[myid] = 1;
    pthread_cond_broadcast(&thread_data->conds[myid]);
    pthread_mutex_unlock(&thread_data->mutexes[myid]);

    // Lock buddy mutex and wait for the buddy thread to reach the same sync point and stride
    pthread_mutex_lock(&thread_data->mutexes[buddy]);
    while (
             thread_data->sync_points[buddy] != sync_point ||
             thread_data->strides[buddy] != stride) {
        pthread_cond_wait(&thread_data->conds[buddy], &thread_data->mutexes[buddy]);
    }
    //thread_data->ready[buddy] = 0;
    pthread_mutex_unlock(&thread_data->mutexes[buddy]);
}

Приведенный выше код пытается реализовать этот сигнал и ждать нескольких идентификаторов потока. Проблема в том, что дело зашло в тупик. Каков правильный способ синхронизации двух потоков среди N потоков, которые могут захотеть взаимодействовать с одним и тем же потоком? без внесения слишком больших накладных расходов с ненужными мьютексами.

Просто добавил немного больше объяснений для вас.

Emil Akesson 15.07.2024 19:58

Если A ждет B, а B ждет A, никакая реализация не сможет предотвратить взаимоблокировку.

Scott Hunter 15.07.2024 20:28

@ScottHunter Но должен быть способ правильно синхронизировать два потока, без использования барьеров, которые необходимо инициализировать для каждого взаимодействия.

Emil Akesson 15.07.2024 21:26

AFAICT, барьерам pthread нужен один вызов init и один вызов уничтожения, но может быть много вызовов ожидания

Craig Estey 15.07.2024 21:54

Я не уверен, что выполняю здесь требования. Можно ли в данный произвольный момент времени разделить потоки на непересекающиеся множества тех, кто ожидает сигнала, и тех, кто отправляет сигнал? Или данный поток может одновременно ожидать получения и пытаться отправить? (И если да, то как это должно работать?) Когда вы говорите «поток может сигнализировать», вы имеете в виду pthread_cond_signal(), или мы могли бы вместо этого сказать «[попытаться] отправить сообщение»?

John Bollinger 15.07.2024 22:21

Не по теме, но... зачем вам (или думаете, что вам нужна) эта функциональность? У вас есть вариант использования? Разработка такой общей системы блокировки/сигнализации, в то же время гарантирующей отсутствие взаимоблокировок, является - по крайней мере для меня - огромной задачей (если я не неправильно прочитал требования).

G.M. 15.07.2024 22:33
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Код в вашем вопросе выглядит нормально для реализации описанной вами схемы. Если предположить, что все переменные инициализированы правильно, проблема, скорее всего, заключается в том, как вы используете эту функцию, поскольку она весьма склонна к взаимоблокировке, если логика вашей вызывающей программы ошибочна.

Если, например, у вас есть вызов потока A signal_and_wait_for_thread(data, ID_A, ID_B, 1, 10); и поток B вызывает signal_and_wait_for_thread(data, ID_B, ID_A, 1, 20);, то это, очевидно, заблокируется: поток A будет ждать, пока поток B установит шаг 10, а поток B будет ждать, пока поток A установит шаг 20, и ни один из них никогда не сможет добиться прогресса.

Ответ принят как подходящий
void wait_for_buddy(thread_data_t * thread_data, int myid, int buddy) {

    pthread_mutex_lock( & thread_data -> mutexes[buddy + 1]);

    while (!thread_data -> ready[myid][buddy]) {

            pthread_cond_wait( & thread_data -> conds[buddy], & thread_data -> mutexes[buddy + 1]);
    }
    thread_data -> ready[myid][buddy] = 0; // Reset for next sync point
    pthread_mutex_unlock( & thread_data -> mutexes[buddy + 1]);

}

void signal_ready(thread_data_t * thread_data, int myid, int buddy) {

        pthread_mutex_lock( & thread_data -> mutexes[myid + 1]);
        thread_data -> ready[buddy][myid] = 1;
        pthread_cond_broadcast( & thread_data -> conds[myid]);
        pthread_mutex_unlock( & thread_data -> mutexes[myid + 1]);

}

Другие вопросы по теме