Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 17:20
Оценка:
Добрый день!

Есть проект, написанный на С, в котором есть глобальная структура. Указатель на эту структуру используется в нескольких функциях как для записи, так и для чтения данных в/из этой структуры. Прект однопоточный.

Есть намерение в другом проекте (С++/С) эффективно использовать каждую из таких функций в отдельном потоке. Понятно, что при этом необходимо обеспечить корректный доступ к полям этой глобальной структуре из разных потоков. Код этих функций крайне желательно не менять (первый проект пишется другой группой, очень не хочется им мешать); в крайнем случае можно его заменять с помощью препроцессора. Дописывать код (например, wrapper functions или свои классы) вполне можно.

Какие есть идеи по корректному использованию такой глобальной структуры при минимальном изменении кода существуюших функций?

С уважением,
Геннадий Майко

P.S. У меня есть пару соображений, но я специально пока не буду их озвучивать здесь, чтобы сначала послушать мнения уважаемых коллег.
Re: Использование структуры в многопоточном приложении
От: jerry_ru  
Дата: 15.03.10 17:29
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

ГМ>Какие есть идеи по корректному использованию такой глобальной структуры при минимальном изменении кода существуюших функций?


1. Если надо написать быстро, то можно использовать своеобразный getter, который возвращает pair<mutex_lock, resource*>.
2. Если API небольшой то можно полность инкапсулировать код, продублировать интерфейс, и более-менее эффективо использовать ресурс.
Re: Использование структуры в многопоточном приложении
От: Vamp Россия  
Дата: 15.03.10 17:31
Оценка:
ГМ>Какие есть идеи по корректному использованию такой глобальной структуры при минимальном изменении кода существуюших функций?
Я что-то не понял, в чем подвох. Использовать обертки, в которых применять объекты синхронизации перед вызовом оригинальных функций. Или я чего-то не уловил?
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 17:34
Оценка:
Здравствуйте, Vamp,

ГМ>>Какие есть идеи по корректному использованию такой глобальной структуры при минимальном изменении кода существуюших функций?

V>Я что-то не понял, в чем подвох. Использовать обертки, в которых применять объекты синхронизации перед вызовом оригинальных функций. Или я чего-то не уловил?
--
В своих (новых) функциях я так смогу сделать, а вот как это сделать в старом коде, который менять не хочется?

C уважением,
Геннадий Майко.
Re[2]: Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 17:38
Оценка:
Здравствуйте, jerry_ru,

ГМ>>Какие есть идеи по корректному использованию такой глобальной структуры при минимальном изменении кода существуюших функций?


_>1. Если надо написать быстро, то можно использовать своеобразный getter, который возвращает pair<mutex_lock, resource*>.

--
Не будет ли здесь проблем с кодом типа:

{
...
ptStrcut->FieldA = 20;
ptStrcut->FiedlB = ptStruct->FiledC;
int LocalVar = ptStruct->FieldD;
...
}

_>2. Если API небольшой то можно полность инкапсулировать код, продублировать интерфейс, и более-менее эффективо использовать ресурс.

--
Увы, интерфейс (т.е. объем структур) очень большой. Наверное, будет сделать трудно.

C уважением,
Генадий Майко.
Re[3]: Использование структуры в многопоточном приложении
От: Vamp Россия  
Дата: 15.03.10 17:43
Оценка:
ГМ>В своих (новых) функциях я так смогу сделать, а вот как это сделать в старом коде, который менять не хочется?
Планируется одновременно обращаться к объектам и из старого проекта, и из нового? Сдается мне, что это не очень хорошая мысль.
Да здравствует мыло душистое и веревка пушистая.
Re[4]: Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 17:57
Оценка:
Здравствуйте, Vamp,

ГМ>>В своих (новых) функциях я так смогу сделать, а вот как это сделать в старом коде, который менять не хочется?

V>Планируется одновременно обращаться к объектам и из старого проекта, и из нового? Сдается мне, что это не очень хорошая мысль.
--
Нет, одновременно будет работать или старый, или новый проект (в котором будут исползоваться "as is" функции старого проекта).

C уважением,
Геннаддий Майко.
Re[3]: Использование структуры в многопоточном приложении
От: jerry_ru  
Дата: 15.03.10 18:04
Оценка: 2 (1)
Здравствуйте, Геннадий Майко, Вы писали:

ГМ>Не будет ли здесь проблем с кодом типа:


ГМ>{

ГМ>...
ГМ>ptStrcut->FieldA = 20;
ГМ>ptStrcut->FiedlB = ptStruct->FiledC;
ГМ>int LocalVar = ptStruct->FieldD;
ГМ>...
ГМ>}

Да вроде недолжно:
{
    pair<locker, resource*> p = get_resource();
    p.second->FieldA = 20;
    p.second->FieldB = p.second->FieldC;
    int LocalVar =  p.second->FieldD;
}


Но надо быть внимательным .
Re[5]: Использование структуры в многопоточном приложении
От: Vamp Россия  
Дата: 15.03.10 18:05
Оценка:
ГМ>Нет, одновременно будет работать или старый, или новый проект (в котором будут исползоваться "as is" функции старого проекта).
Ну тогда я не вижу проблемы. Переименовываешь старые функции в ..._thread_unsafe и заводишь новые — с именами старых, но объектами синхронизации.
Да здравствует мыло душистое и веревка пушистая.
Re: Использование структуры в многопоточном приложении
От: ioni Россия  
Дата: 15.03.10 18:12
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

ГМ>Добрый день!


Так а что мешает завести функцию в которой вы будете менять/чиать значения поля
как нибудь так

template <typename T>
void set_value( ... )
{
   ... lock(guard);
   ...
   ... unlock;
}


причем локер может быть как глобальный так и локальный
Re[4]: Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 18:23
Оценка:
Здравствуйте, jerry_ru,

ГМ>>Не будет ли здесь проблем с кодом типа:


ГМ>>{

ГМ>>...
ГМ>>ptStrcut->FieldA = 20;
ГМ>>ptStrcut->FiedlB = ptStruct->FiledC;
ГМ>>int LocalVar = ptStruct->FieldD;
ГМ>>...
ГМ>>}

_>Да вроде недолжно:

_>
_>{
_>    pair<locker, resource*> p = get_resource();
_>    p.second->FieldA = 20;
_>    p.second->FieldB = p.second->FieldC;
_>    int LocalVar =  p.second->FieldD;
_>}
_>


_>Но надо быть внимательным .

--
Теперь понятно.

Первую проблему здесь я вижу в эффективности — один locker во всех потоках. Но я могу попытаться использовать разные locker для доступа к разным частям структуры.

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

C уважением,
Шеннадий Майко.
Re[6]: Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 18:44
Оценка:
Здравствуйте, Vamp,

ГМ>>Нет, одновременно будет работать или старый, или новый проект (в котором будут исползоваться "as is" функции старого проекта).

V>Ну тогда я не вижу проблемы. Переименовываешь старые функции в ..._thread_unsafe и заводишь новые — с именами старых, но объектами синхронизации.
--
Именно так я и делаю, когда могу выделить функцию.

Но я не хочу переписывать функции, в которых встречается код типа:
{
...
ptStrcut->FieldA = 20;
ptStrcut->FiedlB = ptStruct->FieldC;

int LocalVar = ptStruct->FieldD;
...
}

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

C уважением,
Геннадий Майко.
Re[2]: Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 18:49
Оценка:
Здравствуйте, ioni,

I>Так а что мешает завести функцию в которой вы будете менять/чиать значения поля

I>как нибудь так

I>
I>template <typename T>
I>void set_value( ... )
I>{
I>   ... lock(guard);
I>   ...
I>   ... unlock;
I>}
I>


I>причем локер может быть как глобальный так и локальный

--
Да, я могу сделать по функции на каждое поле структуры и использовать их в моих функция, хотя это и муторно. А как их использовать в старом коде:
{
...
ptStrcut->FieldA = 20;
ptStrcut->FiedlB = ptStruct->FieldC;

int LocalVar = ptStruct->FieldD;
...
}

C уважением,
Геннадий Майко.
Re[7]: Использование структуры в многопоточном приложении
От: Vamp Россия  
Дата: 15.03.10 18:52
Оценка:
ГМ>Потому что завтра функции старого проекта могут изменится и мне будет тяжело за ним уследить.
Понял. Я бы ввел шаг прекомпиляции со скриптом — который бы заменил имена функций в определениях, но оставил бы их в вызовах. Благо, для С это нетрудно сделать.
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Использование структуры в многопоточном приложении
От: alsemm Россия  
Дата: 15.03.10 19:13
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

ГМ>Да, я могу сделать по функции на каждое поле структуры

Синхронизация, в общем случае, делается не на доступ к отдельным полям, а на операции с объектом. Я бы начал с того, что выделил интерфейс доступа к вашему глобальному объекту и чтобы доступ к полям был только через этот интерфейс. А дальше бы уже занимался навешиваем всяких guard-ов на этот интерфейс. Если тупо оставить все как есть и синхронизировать обращения к полям, то толку будет мало.
Re[3]: Использование структуры в многопоточном приложении
От: ioni Россия  
Дата: 15.03.10 19:39
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

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

void function_thread_safe(...)
{
    ... lock(guard);
    legacy_function(...);
}
Re[4]: Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 19:48
Оценка:
Здравствуйте, alsemm,

ГМ>>Да, я могу сделать по функции на каждое поле структуры

A>Синхронизация, в общем случае, делается не на доступ к отдельным полям, а на операции с объектом. Я бы начал с того, что выделил интерфейс доступа к вашему глобальному объекту и чтобы доступ к полям был только через этот интерфейс. А дальше бы уже занимался навешиваем всяких guard-ов на этот интерфейс. Если тупо оставить все как есть и синхронизировать обращения к полям, то толку будет мало.
--
Да, идея неплохая. Вот я и придумаваю, как мне встроить какой-то интерфейс к моему глобальному объекту в существующий код, желательно без замены этого кода.

C уважением,
Геннадий Майко.
Re[4]: Использование структуры в многопоточном приложении
От: Геннадий Майко США  
Дата: 15.03.10 19:57
Оценка:
Здравствуйте, ioni,

I>Так зачем и переписывать, что мешает использовать так как есть

I>вызывая одну через другую как уже здесь советовали

I>
I>void function_thread_safe(...)
I>{
I>    ... lock(guard);
I>    legacy_function(...);
I>}
I>

--
Да, так можно сделать.
Правда при одном и том же guard для всех функций IMHO эффективность резко упадет, потому что только одна функция потока legacy_function будет выполняться в одно и тоже время. Поэтому хотелось бы как-то обеспечить синхронизацию непосредственно при использовании полей структуры.

C уважением,
Геннадий Майко.
Re[5]: Использование структуры в многопоточном приложении
От: jerry_ru  
Дата: 15.03.10 21:07
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:


I>>
I>>void function_thread_safe(...)
I>>{
I>>    ... lock(guard);
I>>    legacy_function(...);
I>>}
I>>

ГМ>--
ГМ>Да, так можно сделать.
ГМ>Правда при одном и том же guard для всех функций IMHO эффективность резко упадет, потому что только одна функция потока legacy_function будет выполняться в одно и тоже время. Поэтому хотелось бы как-то обеспечить синхронизацию непосредственно при использовании полей структуры.

Ну можно сделать примерно так:

//гдето наверху может в синглтоне
guard full_guard;
guard write_guard;
guard read_guard;
...

//а в коде писать
{
#ifndef OLD_ONE_THREAD
   scoped_lock(guard);
#endif

//а дальше вроде не менять ничего. 
}


Ну и манипулировать гуардами для пущей гибкости. Хотя тут конечно очень многое зависит от кода.

тут не стоит говорить об эффективности, но как одно из самых простых решений прохляет... наверное.
Re: Использование структуры в многопоточном приложении
От: Pavel Dvorkin Россия  
Дата: 16.03.10 08:40
Оценка: 4 (1)
Здравствуйте, Геннадий Майко, Вы писали:



struct A {
    int nValue;
}; // твоя структура

struct AX : A {
    int& fnValue() {return nValue;}
}; // а это я добавил - по члену на каждое поле

#define A AX
#define nValue fnValue()

int _tmain(int argc, _TCHAR* argv[])
{
// это твоя исходная программа, я тут ничего не меняю

    A a;
    a.nValue = 10;
    A* pa = &a;
    pa->nValue = 100;

    return 0;
}


Все обращения к полям перехвачены, ставь lock в перехватчиках.
With best regards
Pavel Dvorkin
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.