Má to jedno zásadní omezení. Je to zamykání jen po dobu volání jedné metody a mezi nimi mi ten objekt může nějaký jiný thread překopat. Zrovna první ukázka kódu by měla být podezřelá. Pokud chci na nějaký objekt volat víc metod po sobě, pak má nejspíš zamykání jednotlivých metod příliš jemnou granularitu.
Ve výsledku se tímhle způsobem nedá jednoduše ochránit libovolný objekt u kterého se se zamykáním nepočítalo. Ten objekt musí být navržený stylem jedna metoda = jedna transakce.
Zkusit tímhle způsobem obalit třeba nějaký std kontejner je cesta do pekel.
Teď nechápu "jak vůbec nemá". V původním návrh samozřejmě šipka je
namespace std
{
template<typename T>
class synchronized_value
{
public:
synchronized_value(synchronized_value const&) = delete;
synchronized_value& operator=(synchronized_value const&) = delete;
template<typename ... Args>
synchronized_value(Args&& ... args);
~synchronized_value();
template<typename F>
auto apply(F&& func) -> typename std::result_of<F(T&)>::type;
unspecified operator->();
unspecified operator*();
};
}
Odpověď na první otázku bys našel v tom videu. Mají tam něco čemu říkají "update_guard", který zamkne objekt na dobu, kdy je guard aktivní. Já to tak nemám, protože podobnou funkcionalitu zařídí právě metody lock() a lock_shared()
auto guard = sync_object.lock();
guard->method1();
guard->method2();
Sám si nejsem jist, co je lepší řešení.
Jinak z hlediska návrhu kódu, trochu bych se ohradil proti myšlence, že chci nějakou činnost objektu realizovat sekvenčním voláním několika metod. Objekt navrhuju primárně tak, aby metoda = transakce. To jen na okraj.
V úplně prvním návrhu jo, ale ve všech dalších verzích už je jenom to apply. I ten guard vypadl, asi proto, že celou jeho funkci zvládne pokrýt to obecnější apply. Ten operator-> určitě nevyhodili proto, že by to bylo těžké implementovat. A pan Hoare by určitě potvrdil, že bychom neměli přidávat věci jen proto, že to jde jednoduše udělat :)
Jo, můžete použít guard/lock/apply. Jenže ten operátor-> docela pravděpodobně navede nezkušeného programátora k tomu, že to nepoužije. Nebude bádat, jak psát divný kód, když mu funguje ten normální. A že je tam zádrhel mu nemusí v nějaké slabší chvilce dojít. IMO je to ukázkový příklad "design induced error".
A objektů kde metoda!=transakce jsou mraky. Kromě kontejnerů jsou to věci kde jedna metoda vrací počet a jiná bere indexy. Nebo třeba metody, které je možné volat jen na validním objektu (třeba dvojice operator bool + operator() u std::function).
Intenzivně se zabývám programováním zejména v jazyce C++. Vyvíjím vlastní knihovny, vzory, techniky, používám šablony, to vše proto, aby se mi usnadnil život při návrhu aplikací. Pracoval jsem jako programátor ve společnosti Seznam.cz. Nyní jsem se usadil v jednom startupu, kde vyvíjím serverové komponenty a informační systémy v C++
Přečteno 50 603×
Přečteno 23 674×
Přečteno 22 664×
Přečteno 20 632×
Přečteno 17 622×