2014-01-22 6 views
0

На моем многопоточном сервере у меня есть somefunction(), который должен защитить две независимые друг от друга глобальные данные, используя EnterCriticalSection.make function exception-safe

somefunction() 
{ 
    EnterCriticalSection(&g_List); 
    ... 
    EnterCriticalSection(&g_Variable); 
    ... 
    LeaveCriticalSection(&g_Variable); 
    ... 
    LeaveCriticalSection(&g_List); 
} 

Следуя советам лучших программистов, я собираюсь использовать обертку RAII. Например:

class Locker 
{ 
    public: 
    Locker(CSType& cs): m_cs(cs) 
    { 
    EnterCriticalSection(&m_cs); 
    } 
    ~Locker() 
    { 
    LeaveCriticalSection(&m_cs); 
    } 
    private: 
    CSType& m_cs; 
} 

Мой вопрос: Это нормально, чтобы превратить somefunction() к этому? (ввод 2 Locker в одной функции):

somefunction() 
{ 
// g_List,g_Variable previously initialized via InitializeCriticalSection 

    Locker lock(g_List); 
    Locker lock(g_Variable); 
    ... 
    ... 
} 

?

ответ

1

Ваше текущее решение имеет потенциал dead lock кейс. Если у вас есть два (или более) CSType s, которые будут заблокированы в другом порядке таким образом, вы окажетесь в мертвой блокировке. Лучшим способом было бы зафиксировать их как атомарно. Вы можете увидеть пример этого в библиотеке boost thread. shared_lock и unique_lock могут использоваться в отложенном режиме, чтобы сначала вы подготовили все объекты raii для всех объектов мьютекса, а затем заблокировали их все атомически одним вызовом функции lock.

+0

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

+0

Да, но практика показывает, что это действительно сложно сделать с любым нетривиальным приложением. – tumdum

1

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

{ 
    // use inner scopes to control lock duration 
    { 
     Locker lockList (g_list); 
     // do something 
    } // unlocked at the end 

    Locker lockVariable (g_variable); 
     // do something 
} 
+0

Если я поставил эти дополнительные скобки, все проблемы, упомянутые Томашем Клаком, исчезнут? – maciekm

+1

Нет, вам нужно поддерживать один и тот же порядок блокировок во всех потоках, код, который я дал, - это просто показать, что позволяет заблокировать блокировку. – mindo