Чтение переменной портит? - PullRequest
2 голосов
/ 21 мая 2010

У нас есть следующая строка кода:

printf("%d\n", toc->runlist.next);
printf("%d\n", toc->runlist.next);

Это определения:

typedef struct thread_overview_control{
    int id[NR_UTHREADS];
    list_t runlist;
    int active_counter;
    int main_thread;
    int need_resched;
} thread_overview_control;

thread_overview_control* toc;

Я пытаюсь реализовать пользовательские потоки. По какой-то причине результат вышеприведенного кода в точке, где наш тестовый прогон падает:

12345678  //some address
0         //NOW IT'S NULL?!?!?!

Как это может произойти ?? Все, что мы делаем, это читаем переменную. И что странно, без printf нет сбоев. Что происходит?

Ответы [ 5 ]

3 голосов
/ 21 мая 2010

Скорее всего, другой поток обращается (и изменяет) переменную между вашими двумя вызовами printf (). Если вы удалите операторы printf, время изменится, а поведение будет другим.

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

1 голос
/ 21 мая 2010

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

Другая возможность - это простой старый дикий указатель. Как вы инициализируете toc? Если он в конечном итоге указывает на освобожденную стековую память, первый вызов printf() может довольно легко растоптать его.

1 голос
/ 21 мая 2010

Попробуйте запустить вашу программу под valgrind. Он укажет на любые ошибки, связанные с памятью, которые могут у вас возникнуть.

1 голос
/ 21 мая 2010

printf() не изменяет свои переменные аргументы. Тем не менее, printf() - это операция, стоимость которой достаточна для выявления рас, вызванных отсутствием (или неправильной) блокировкой между потоками.

То, что вы хотите использовать, это мьютекс:

pthread_mutex_t thread_lock = PTHREAD_MUTEX_INITIALIZER;

void *thread_func(void *threadarg)
{
    thread_overview_control *toc = (thread_overview_control *)threadarg;

    pthread_mutex_lock(&thread_lock);
    printf("%d\n", toc->runlist.next);
    printf("%d\n", toc->runlist.next);
    pthread_mutex_unlock(&thread_lock);

    ....

В этом примере pthread_mutex_lock() будет блокироваться, если другой поток заблокирован. Если ваша функция может выполнять другую полезную работу в ожидании блокировки, попробуйте pthread_mutex_trylock(), возможно, в цикле while().

Просто убедитесь, что каждый поток может добраться до мьютекса, сделав его глобальным (или поместив его в структуру, к которой у каждого есть доступ). В равной степени важно инициализировать мьютекс с помощью PTHREAD_MUTEX_INITIALIZER, иначе вы рискуете удержать блокировку без какого-либо потока, фактически удерживающего ее.

Всякий раз, когда вы читаете или пишете в *toc, вам необходимо получить блокировку.

0 голосов
/ 21 мая 2010

Что такое list_t? Это простой C? Имейте в виду, что можно имитировать "свойство" (своего рода) в C ++, так что вызов runlist.next фактически вызывает некоторый метод, это может быть скрытый итератор.

Ответ Вики мне кажется более вероятным.

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