Приостановите pthreads, не используя условие

Я хочу приостановить pthreads, но по-видимому, нет такой функции как pthread_suspend. Я считал где-нибудь о приостановке pthreads использование взаимных исключений и условий и использовал его в качестве следующего:

#include <pthread.h>

class PThread {
public:
pthread_t myPthread;
pthread_mutex_t m_SuspendMutex;
pthread_cond_t m_ResumeCond;

void start() {
pthread_create(&myPthread, NULL, threadRun, (void*)this );
}

Thread() { }

void suspendMe() {
pthread_cond_wait(&m_ResumeCond,&m_SuspendMutex);
}

void resume() {
pthread_cond_signal(&m_ResumeCond);
}
};

но я не понимаю, почему нам нужны и взаимное исключение и в условие приостановить и возобновить pthread. Действительно ли возможно приостановить и возобновить его, не используя условия?

7
задан caf 29 June 2010 в 13:27
поделиться

5 ответов

Ваш код неверен - pthread_cond_wait () требует, чтобы мьютекс был заблокирован уже при его вызове:

void suspendMe()
{
    pthread_mutex_lock(&m_SuspendMutex);
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
    pthread_mutex_unlock(&m_SuspendMutex);
}

Однако это все еще неверно. Поток может проснуться из pthread_cond_wait () под любым именем, не обязательно только тогда, когда он получил сигнал. Это означает, что вам нужно связать pthread_cond_wait () с некоторым разделяемым состоянием, которое кодирует условие, которого поток действительно ожидает - в простейшем случае вы можете просто использовать переменную флага. pthread_cond_signal () используется, чтобы сообщить потоку, что он должен пробудиться и повторно проверить общее состояние. Применяя это к вашей реализации:

class PThread {
    public:

    pthread_t myPthread;
    bool suspended;
    pthread_mutex_t m_SuspendMutex;
    pthread_cond_t m_ResumeCond;

    void start() {
        suspended = false;
        pthread_create(&myPthread, NULL, threadRun, (void*)this );
    }

    Thread() { }

    void suspendMe() {
        pthread_mutex_lock(&m_SuspendMutex);
        suspended = true;
        do {
            pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
        } while (suspended);
        pthread_mutex_unlock(&m_SuspendMutex);
    }

    void resume() {
        /* The shared state 'suspended' must be updated with the mutex held. */
        pthread_mutex_lock(&m_SuspendMutex);
        suspended = false;
        pthread_cond_signal(&m_ResumeCond);
        pthread_mutex_unlock(&m_SuspendMutex);
    }
};

Причина, по которой мьютекс предоставляется, состоит в том, чтобы защитить общее состояние и избежать условий гонки - функция pthread_cond_wait () фактически выполняет атомарную разблокировку и ожидание, когда она ожидает , что позволяет избежать «пропущенного пробуждения». Например, в этом коде мьютекс предотвращает изменение приостановленного на false между строками Suspen = true; и pthread_cond_wait () .

8
ответ дан 6 December 2019 в 15:18
поделиться

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

Разбудить поток, не сказав ему, почему вы его разбудили, - это немного странно, поэтому нет специального способа сделать это; единственный способ сделать это - использовать обычный механизм, но без общего состояния.

Если по какой-то причине вы хотите приостановить и возобновить поток из другого потока, независимо от того, чтобы дать ему работу, вы можете использовать pthread_kill , чтобы отправить его SIGSTOP ] и SIGCONT сигналы; Я никогда не пробовал делать что-то подобное, поэтому понятия не имею, поддерживается ли это.

2
ответ дан 6 December 2019 в 15:18
поделиться

Если поток не ждал при каком-либо условии, как вы могли «сигнализировать» ему о возобновлении. Он не может просто прекратить выполнение чего-либо, а затем волшебным образом начать снова, поэтому он ждет с условием.

Чтобы уточнить, в pthreads способ возобновления потока на самом деле заключается в использовании условных переменных. Нет API, доступного для приостановки / возобновления потока каким-либо другим способом. Ожидание на pthread_cond_wait дешево, оно блокируется до тех пор, пока не будет сигнализировано условие, без использования (много?) ЦП. Вы используете условие, чтобы сигнализировать потоку о пробуждении, а мьютекс требуется для защиты доступа к переменной условия и коду в потоке после пробуждения.

5
ответ дан 6 December 2019 в 15:18
поделиться

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

Мьютексы нужны нам для того, чтобы переменные условий не попадали в бесконечное ожидание. Следует помнить, что операции Mutex по блокировке и разблокировке гарантированно атомарны, но для переменных условий это не так. Т.е. поток может быть запланирован, пока переменная условия ждет половину пути.

Рассмотрим следующий случай с отсутствием Mutex для переменной условия.

Поток 1


1)Выполнить некоторую операцию
2)Ожидание переменной условия
3)Продолжает операцию

Поток 2


1)Выполняет некоторую операцию
2)Подать сигнал на переменную условия
3)Продолжить операцию

Здесь, в Потоке 1, шаг 2 не гарантированно атомарный. Если планировщик выведет поток 1 из состояния RUNNING до того, как он завершит шаг 1. Нить 2 начнет выполнение и подаст сигнал переменной условия. Когда поток 1 возобновит выполнение, он завершит оставшиеся инструкции низкого уровня и начнет ждать. Нить 1 попадает в бесконечное ожидание, так как сигнал переменной условия произошел еще до начала ожидания.

Итак, правильнее всего использовать следующий способ (я полагаю, что код, упомянутый в вопросе, не делает ожидаемого)

Thread 1 :-


1)Выполнить работу до момента, когда должно наступить определенное условие (например, "count" должен достичь заданного значения)
2)Заблокировать связанный мьютекс
3)Вызовите pthread_cond_wait() для выполнения блокирующего ожидания сигнала от Thread1. (Обратите внимание, что вызов pthread_cond_wait() автоматически и атомарно разблокирует связанную переменную mutex, чтобы ее мог использовать Thread2)
4)По сигналу проснуться. Мьютекс автоматически и атомарно блокируется.
5)Явно разблокировать мьютекс

Thread2


1)Выполнить работу
2)Заблокировать связанный мьютекс
3)Изменить значение глобальной переменной, которую ожидает Thread1.
4)Проверьте значение глобальной переменной ожидания Thread1. Если оно удовлетворяет требуемому условию, подайте сигнал Thread1.
5)Разблокируйте мьютекс. Продолжить

0
ответ дан 6 December 2019 в 15:18
поделиться

Ближе к делу - что вы в конечном итоге пытаетесь сделать ?? - Я подозреваю, что ответ не «приостановить обсуждение». Возможно, в вашей программе возникла проблема.

-1
ответ дан 6 December 2019 в 15:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: