2013-06-27 2 views
0

Рассмотрим следующий код:предотвращения возможных данных Условия гонки

typedef double (*fpointer)(void*); 

typedef struct { 
    int data1; 
    double data2; 
} data_t; 

double stuff(void* arg) { 
    data_t *d = (data_t *)arg; 
    ... 
    // Do random things 
    ... 
    return data2; 
} 

И считают меня неблокируемому функцию:

void func(fpointer f, data_t* d) 

, который по существу проходит f(d) но возвращается сразу, не дожидаясь f(d) к полный (похоже на что-то вроде MPI_Isend/MPI_Irecv).

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

data_t d; 
d.data1 = 1; 
d.data2 = 1.5; 

for (int i = 0; i < 1000; i++) { 
    d.data2 += 1.0; 
    func(stuff, &d); 
} 

Если вам нужно больше пояснений, пожалуйста, дайте мне знать. Я ценю любую помощь.

+0

Является ли ваш код многопоточным? Если так, то каким образом)? – Patashu

+0

Технически да. Многопоточность происходит от вызова функции func. Я использую qthreads (http://www.cs.sandia.gov/qthreads/), который выполняет параллелизм на основе задач. 'func' - это функция для функции' qthread_fork (...) '. –

+0

Определение * гонка данных * - это «два или более одновременных доступа к одному и тому же объекту, по крайней мере один из которых является записью». Если 'func' организует другой поток для запуска' stuff (d) ', это гонка данных. – Casey

ответ

1

Небезопасно вообще - если, как вы подразумеваете, в фоновом режиме происходит обработка. Вы повторно используете тот же экземпляр d для каждой итерации; d передается по ссылке.

Рассмотрите возможность сделать новую копию d или используя pass-by-copy в func. Поскольку data_t относительно невелик, в этом случае вы не будете сильно ударять.

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

+0

К сожалению, я вынужден использовать подпись 'func', поэтому мне нужно передать указатель. –

+0

@AlexBrooks Вы можете сделать новую копию и передать указатель на новую копию – Patashu

+0

@RichardSitze, к сожалению, у меня нет доступа для изменения 'func'. Все, что я делаю, должно быть сделано за пределами 'func' - это функция библиотеки. –