Требуется ли для этого раздела кода мьютекс? - PullRequest
1 голос
/ 19 марта 2011

Я пытаюсь реализовать грубое прерывание потока.

Переменная 'interruptRequested' проверяется довольно часто. В классе «Операционные системы» мы узнали о голодании - возможно ли это здесь или в аналогичной ситуации? Я знаю, что пример программы ведет себя так, как я ожидал, когда я ее запускаю, но это может быть просто случайность.

Вот упрощенная версия того, что я делаю:

//Compile with -lpthread

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>

using namespace std;

bool interruptRequested;
pthread_mutex_t spamMutex;
void *Spam(void *); 

int main(int argc, char *argv[])
{   

pthread_t tid; 

interruptRequested = false;

unsigned long long int timeStarted = time(NULL);
pthread_create(&tid, NULL, Spam, NULL);
unsigned long long int difference = 0;


while (true)
{
    pthread_yield();
    difference = (time(NULL) - timeStarted);
    if ( difference >= 5)//Spam the terminal for 5 seconds
    {
        //while (pthread_mutex_trylock(&spamMutex));
        interruptRequested = true;
        //pthread_mutex_unlock(&spamMutex);
        break;
    }


}

return 0;
}

void *Spam (void *arg)
{
while (true)
{
    //while (pthread_mutex_trylock(&spamMutex));
    if (interruptRequested == true)
    {
        //pthread_mutex_unlock(&spamMutex);
        break;
    }
    //pthread_mutex_unlock(&spamMutex);
    cout << "I'm an ugly elf" << endl;
    pthread_yield();
}

interruptRequested = false;
pthread_exit (0); 
}

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

Ответы [ 3 ]

1 голос
/ 19 марта 2011

Как написано, этот код не обязательно должен работать, потому что компилятор может оптимизировать проверку для interruptRequested внутри рабочего потока, потому что он никогда не пишется внутри функции. Это будет означать, что в сгенерированном коде может быть просто цикл while (true) (или что-то эквивалентное ему).

Чтобы этого не происходило, вам нужно как-то убедиться, что компилятор распознает, что переменная может быть изменена в другом месте. Вы можете сделать это, пометив interruptRequested volatile, что указывает компилятору, что его не следует оптимизировать. Использование мьютекса также является хорошей идеей, поскольку большинство компиляторов достаточно умны, чтобы признать, что использование мьютекса указывает на то, что переменные, на которые ссылается мьютекс, могут быть изменены извне.

0 голосов
/ 20 марта 2011

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

, даже если работает , как ожидается, на самом деле это может быть не так. 99% успеха не принимаются в программном обеспечении. Кроме того, ваша тестовая программа тривиальна - велика вероятность, что она (молча или таинственно) потерпит неудачу в реальном мире.

использование volatile (или атомики, во многих случаях) в качестве замены для блокировки - это плохая идея. эта модель в конечном итоге выйдет из строя, хотя часто кажется для правильной работы при небольших нагрузках. Есть несколько угловых случаев, но вы должны отказаться от ассоциаций volatile, являющихся заменой правильной конструкции, в которой используется блокировка. на самом деле вы можете проверить это, сделав interruptRequested an int и используя только увеличение / уменьшение. под большими нагрузками - вы можете быстро превысить [0 ... 1].

вы будете часто использовать volatile и / или atomics при объявлении / чтении / записи interruptRequested (опять же, я рекомендую проверки int / inc / dec / bounds, особенно во время обучения). если чтение и запись заблокированы (что и должно быть в данном случае), использование атомарных операций чтения / записи не поможет.

относительно вашей программы, условия (pthread_cond_t) могут быть хорошим выбором.

0 голосов
/ 19 марта 2011

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

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

...