Приостановить pthreads без использования условия - PullRequest
7 голосов
/ 29 июня 2010

Я хочу приостановить 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. Можно ли приостановить и возобновить его без использования условий?

Ответы [ 6 ]

8 голосов
/ 29 июня 2010

Ваш код неверен - 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() с некоторым общим состоянием, которое кодирует условие, которого действительно ожидает поток - в простейшем случае вы можете просто использовать переменную flag. 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() фактически выполняет атомную разблокировку и ожидание при ожидании, что позволяет избежать "пропущенного пробуждения". Например, в этом коде мьютекс предотвращает изменение значения suspended на false между строками suspended = true; и pthread_cond_wait().

5 голосов
/ 29 июня 2010

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

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

2 голосов
/ 29 июня 2010

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

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

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

0 голосов
/ 08 октября 2012

Похоже, что нет никаких альтернатив Linux для функции Windows API SuspendThread.Невозможно приостановить поток Linux без внедрения кода в процедуру этого потока.

0 голосов
/ 29 июня 2010

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

0 голосов
/ 29 июня 2010

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

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

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

Тема 1


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

Тема 2


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

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

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

Тема 1: -


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

Резьба2


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

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