изменчивый и многопоточность? - PullRequest
2 голосов
/ 30 июля 2010

В следующем коде:

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int ready = 0;

wait()
{
    int i;
    do
    {
        usleep(1000);
        pthead_mutex_lock(&mutex);
        i = ready;
        pthread_mutex_unlock(&mutex);
    } while (i == 0);   
    printf("Finished\n");
}

signal()
{
    pthead_mutex_lock(&mutex);
    ready = 1;
    pthread_mutex_unlock(&mutex);
}

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

Теперь код будет вести себя так, как ожидалось, или нам нужно будет сделать его готовым к работе, чтобы заставить его работать? Будут ли разные компиляторы и библиотеки обрабатывать это по-разному?

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

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

Ответы [ 6 ]

2 голосов
/ 31 июля 2010

Некоторые перспективы от королей ядра:

http://kernel.org/doc/Documentation/volatile-considered-harmful.txt

2 голосов
/ 30 июля 2010

Я был бы удивлен, если бы компилятор предполагал что-либо о глобальной переменной при наличии вызовов библиотечных функций. Это сказанное, изменчивый не будет стоить Вам ничего, и это показывает Ваши намерения. Я бы положил его туда.

1 голос
/ 31 августа 2011

Летучий не является ни обязательным, ни достаточным. Так что нет причин использовать его. Этого недостаточно, потому что ни один стандарт не указывает, что он обеспечит видимость между потоками. В этом нет необходимости, потому что стандарт pthreads говорит, что мьютексов достаточно.

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

0 голосов
/ 31 июля 2010

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

Я бы посоветовал использовать volatile в данной ситуации. Хотя в случае, кажется, это не нужно.

IOW, лично я бы добавил volatile и снял блокировку: она не нужна для установки / чтения значения переменной.

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

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

Чтобы быть действительно уверенным, вы хотите проконсультироваться с C99's 5.1.2.3 Program execution, откуда я заимствовал терминологию. Чтобы дать вам вкус:

[...] Доступ к энергозависимому объекту, изменение объекта, изменение файла или вызов функции, выполняющей любую из этих операций, являются побочными эффектами , которые являются изменениями в состоянии среда исполнения. Оценка выражения может привести к побочным эффектам. В определенных точках в последовательности выполнения, называемых точками последовательности , все побочные эффекты предыдущих оценок должны быть завершены, и никаких побочных эффектов последующих оценок не должно быть. (Краткое описание точек последовательности приведено в приложении С.)

В абстрактной машине все выражения оцениваются как указано семантикой. Реальная реализация не должна оценивать часть выражения, если она может сделать вывод, что его значение не используется и что не возникает никаких побочных эффектов (включая любые, вызванные вызовом функции или доступом к энергозависимому объекту). [...]

Выдержка из приложения C:

Ниже приведены точки последовательности, описанные в 5.1.2.3:
. - вызов функции после оценки аргументов (6.5.2.2).

И оттуда.

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

0 голосов
/ 30 июля 2010

Волатильность нужна здесь при наличии оптимизации. В противном случае чтение готовности может быть законно удалено из цикла while.

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

0 голосов
/ 30 июля 2010

да, volatile int ready = 0; здесь всегда нужно.

Обновление
Если вам не нужна оптимизация вокруг некоторого фрагмента кода, вы можете использовать директивы #pragma для этого кода (если ваш компилятор их поддерживает) или - что является полностью переносимым - переместить код в отдельные файлы и скомпилировать эти файлы без или с небольшим количеством оптимизаций.
Последний подход все еще может потребовать использования ключевого слова volatile, поскольку переменная ready может использоваться другими модулями, которые вы можете оптимизировать.

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