2012-02-27 2 views
1

Мое приложение разделено на несколько более мелких доменов, и для уменьшения зависимостей между ними я собираюсь использовать объект контекста. Давайте рассмотрим простой пример:Синхронизация объекта контекста

class SomeType1; 
class SomeType2;  
class dummy; 

//context for first domain 
class foo 
{ 
public: 
    virtual void setPtr1 (SomeType1* val) = 0; 
    virtual SomeType2* getPtr2() = 0; 

    static foo* getCTX() 
    { 
     //statement bellow is a singleton which creates one instance of dummy and 
     //returns its address as foo* 
     return AppCTX::AccessorType<dummy>::getCTX<foo>(); 
    } 
    virtual ~foo(); 
}; 

//context for second domain 
class bar 
{ 
public: 
    virtual void setPtr2 (SomeType2* val) = 0; 
    virtual SomeType1* getPtr1() = 0; 
    static bar* getCTX() 
    { 
     //same as above but casts dummy* to bar* 
     return AppCTX::AccessorType<dummy>::getCTX<bar>(); 
    } 
    virtual ~bar(); 
}; 

//dummy is a singleton created in AppCTX::AccessorType<dummy> 
class dummy: public foo, public bar 
{ 
public: 
    virtual void setPtr1 (SomeType1* val) 
    { 
     ptr1 = val; 
    } 

    virtual SomeType1* getPtr1() 
    { 
     return ptr1; 
    } 

    virtual void setPtr2 (SomeType2* val) 
    { 
     ptr2 = val; 
    } 

    virtual SomeType2* getPtr2() 
    { 
     return ptr2; 
    } 
    virtual ~dummy(); 
private: 
    SomeType1* ptr1; 
    SomeType2* ptr2; 
}; 

Мои домены запускает несколько потоков, которые используют контекст и так ptr1 и ptr2 могут быть доступны параллельно. Нужно ли мне синхронизировать setPtrs и getPtrs с мьютексами? Есть ли вероятность, что ptr1 и ptr2 могут быть повреждены каким-то образом?

ответ

1

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

Вы действительно хотите поместить свои механизмы блокировки в классы SomeType1 и SomeType2. Например, вы можете получить мьютекс в начале каждой функции-члена SomeType1, а затем отпустить мьютекс перед возвратом каждой функции-члена.

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

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