Мои вопросы: сколько значений может принимать вывод следующего кода? Каковы эти ценности? В чем причина разных ценностей? Как мы можем предотвратить появление разных значений?
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>
int shared_data = 100;
void* thread_function(void *args)
{
long temp;
long *j = (long *) args;
temp = shared_data;
temp = temp + &j;
shared_data = temp;
return (NULL);
}
int main()
{
long i = 0;
long tinfo[] = {1,2,3};
pthread_t ids[3];
for(int i=0 ;i<3;i++)
{
pthread_create(ids+i,NULL,&thread_function, &tinfo[i]);
}
for(int i=0 ;i<3;i++)
{
pthread_join(ids[i],NULL);
}
printf("shared data = %d\n",shared_data);
}
Я работал над системным программированием и операционной системой и увидел это упражнение. Я пытался провести исследование, но эта тема для меня очень новая. Это не домашнее задание или вопрос экзамена. Это один из вопросов прошлого собеседования учебного заведения.
long *j = (long *) args;
-- в сторону: вам не нужно приводить указатели void в C.
«Как мы можем предотвратить появление разных ценностей?» - Чтобы получить определенное поведение, синхронизируйте потоки.
Вычисление temp = temp + &j;
сомнительно — вы добавляете к вычислению адрес локальной переменной-указателя. Вероятно, вам следует использовать temp += *j;
, чтобы добавить значение, на которое указывает указатель. Ваш компилятор должен кричать о добавлении — и вы должны обращать внимание на вопли вашего компилятора! Переменная long i = 0;
не используется.
Вероятно, вам понадобится использовать pthread_mutex_t
(мьютекс — взаимное исключение) для управления доступом к shared_data
(см. pthread_mutex_init() и так далее). По крайней мере, это самый простой способ справиться с проблемами одновременного доступа. Это не ускорит процесс, но сделает его более надежным. Последовательность по-прежнему отсутствует — то, что происходит, зависит от своеобразного поведения планирования потоков на вашей конкретной машине — но неопределенного поведения будет меньше.
Первым делом скомпилируйте код с помощью -Wall -Werror
.
В идеале заголовок вашего вопроса должен представлять собой краткое изложение вопроса или ссылаться на его тему. Например, лучшим названием могло бы быть «Общий доступ к данным в pthreads». На самом деле это не пример «системного программирования» — это проблема многопоточности в целом.
Предполагая, что ожидается ответ, а не исправление многих ошибок, которые, вероятно, являются непреднамеренными, при ответе на этот вопрос вам следует сформулировать некоторые предположения, чтобы справиться с «неопределенным» поведением плохо сформированного кода. Это продемонстрирует ваше знание таких вопросов, если вопрос действительно будет об этом, но это также позволит вам ответить на вопрос так, как, вероятно, предполагало учреждение. Они, возможно, даже исправят вопрос для следующего кандидата! К сожалению, мир полон таких некорректных вопросов на собеседовании — если вы хотите поступить на курс, вам нужно сыграть в игру. Но вы можете не захотеть записываться, если это, возможно, свидетельствует о качестве их преподавания.
Во всяком случае, если мы заявим:
Предположения:
shared_data
будет явным, несмотря на отсутствие квалификатора volatile
.Тогда изменчивость вывода будет зависеть от порядка запуска каждого потока, который не обязательно должен совпадать с порядком их создания. Таким образом, речь идет о перестановках 1,2,3, что равно 3 x 2 x 1 = 6. Таким образом, ответ заключается в выполнении вычисления функции потока для каждой из шести возможных перестановок порядка выполнения.
Без допущений результат совершенно не определен.
Учитывая эти предположения, «исправление» состоит в том, чтобы вообще не использовать потоки, а вызывать функцию последовательно в одном фиксированном порядке. Несомненно, существуют более сложные решения, использующие синхронизацию потоков, но нет никакой практической пользы от выполнения потоков до завершения в определенном последовательном порядке.
Все потоки изменяют общие данные без каких-либо средств управления для предотвращения одновременного доступа. Поведение полностью неопределенно, и нет никаких полезных прогнозов, которые можно сделать.