madf: (Default)
[personal profile] madf
Займався проблемою дедлока. Суть у слідуючому: є дві послідовності викликів:
1. TRAFFCOUNTER::SomeMethod1 -> USER::SomeMethod2
2. AUTH::SomeMethod3 -> USER::SomeMethod4 -> (Notifier) -> TRAFFCOUNTER::SomeMethod5
Вони відбуваються у різних потоках і на початку кожного виклику становлюється мьютекс. Звісно іноді виникає дедлок. Для того щоб позбутись цього я вирішив розірвати другий ланцюг по лінії Notifier.
Notifier це такий допоміжний клас що використовується для повідомлення одних об’єктів про зміни у інших. Виклики через Notifier виконуються у тому ж потоці що й подія яка їх викликала (вибачте за каламбур). Щоб не зламати все я вирішив поки що не чіпати систему повідомленнь а зробити чергу "дій" на стороні TRAFFCOUNTER які будуть задаватись Notifier'ом.
Початкова реалізація була проста: структура з двома полями (тип дії і дані) і диспетчер який за типом дії викликав необхідний метод. І вона працювала, але дуже не подобалась мені наявністю switch для диспетчеризації. Тоді я подумав: "Метод який необхідно викликати для виконання дії відомий, можна його вказувати явно і позбутись диспетчера". Для цього структура дещо змінилась:
typedef void (TRAFFCOUNTER::*Actor)(user_iter);
struct Action {
    Actor actor;
    user_iter data;

    Action(Actor a, user_iter d) : actor(a), data(d) {};
};
_Winnie C++ Colorizer

TRAFFCOUNTER зберігає список із таких структур. Notifier додае структуру до списку:
inline
void DEL_USER_NONIFIER::Notify(const user_iter & user)
{
STG_LOCKER(&traffCnt.mutex, __FILE__, __LINE__);
traffCnt.pending.push_back(Action(&TRAFFCOUNTER::UnSetUserNotifiers, user));
traffCnt.pending.push_back(Action(&TRAFFCOUNTER::DelUser, user));
}
_Winnie C++ Colorizer

Сам TRAFFCOUNTER у своєму потоці оброблює дії:
class InvokeAction : public std::unary_function<const Action &, void>
{
public:
    InvokeAction(TRAFFCOUNTER & t) : tc(t) {};
    void operator()(const Action & action);
private:
    TRAFFCOUNTER & tc;
};
_Winnie C++ Colorizer

void TRAFFCOUNTER::ProcessActions()
{
if (pending.empty())
    return;

std::list<Action> local;

    {
    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
    local.swap(pending);
    printfd(__FILE__, "local.size() = %d, pending.size() = %d\n", local.size(), pending.size());
    }

std::for_each(
        local.begin(),
        local.end(),
        InvokeAction(*this)
        );
}
_Winnie C++ Colorizer

Щось мені підказує що все це можна ще більше спростити, але поки не допетрав як.
Upd. Забув викласти найсмачніше:
inline
void InvokeAction::operator()(const Action & action)
{
    // Invoke method action.actor with data action.data
    (tc.*action.actor)(action.data);
}
_Winnie C++ Colorizer
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

Profile

madf: (Default)
madf

April 2018

S M T W T F S
1234567
891011121314
15161718192021
22232425262728
2930     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 7th, 2026 10:24 am
Powered by Dreamwidth Studios