Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: Ondřej Novák 29. 10. 2017, 18:49:18
-
Ve svém kódu jsem začal používat objekt, který funguje obráceně než semafor. Je to counter, který mohu zvyšovat a snižovat a případně mohu nařídit jinému vláknu, aby bylo zastaveno, dokud se na counteru neobjeví nula.
Typicky to používám tak, že chci aby thread počkal, dokud se nedokončí všechny paralelní operace, přičemž stačí počítat, kolik jich ještě běží. Pokud všechny skončí, klesne čítač na nulu a thread může pokračovat.
A teď hledám na google, jak se toto synchronizační primitivum jmenuje. Protože klasický semafor to není, bariera taky ne. Google mi nepomůže, protože se ho neumím zeptat. Pomůže mi někdo?
-
atomic_int ?
-
Třída, která umí jen snižovat, se v Javě jmenuje CountDownLatch. Obecně pak funguje Phaser. Zda to má i nějaké obecné názvy nevím.
-
https://en.wikipedia.org/wiki/Barrier_(computer_science)
nebo taky randezvous
-
Typicky to používám tak, že chci aby thread počkal, dokud se nedokončí všechny paralelní operace, přičemž stačí počítat, kolik jich ještě běží. Pokud všechny skončí, klesne čítač na nulu a thread může pokračovat.
Pro tuhle konkrétní situaci by šlo možná použít nějakou obdobu thread_group z boostu. Nemusel byste se starat o inkrementaci a dekrementaci čítače.
-
Condition variable.
https://en.m.wikipedia.org/wiki/Monitor_(synchronization)
-
Typicky to používám tak, že chci aby thread počkal, dokud se nedokončí všechny paralelní operace, přičemž stačí počítat, kolik jich ještě běží. Pokud všechny skončí, klesne čítač na nulu a thread může pokračovat.
Pro tuhle konkrétní situaci by šlo možná použít nějakou obdobu thread_group z boostu. Nemusel byste se starat o inkrementaci a dekrementaci čítače.
No já to nepoužívám jen na vlákna, ale obecně na počítání úloh. Těch může být víc jak vláken, přičemž některé se vykonávají, jiné jsou ve frontě. Cílem je zastavit nějaké vlákno, dokud nejsou úlohy hotové.
-
Condition variable.
https://en.m.wikipedia.org/wiki/Monitor_(synchronization)
Ano, používám na to condition_variable, chtěl jsem to vyčlenit z projektu a strčit do nějaké společné knihovny a dát tomu rozumný název. Zatím se to jmenuje MTCounter
class MTCounter {
public:
void inc() {
std::unique_lock<std::mutex> _(lock);
counter++;
}
void dec() {
std::unique_lock<std::mutex> _(lock);
if (counter) {
counter--;
if (counter == 0) {
waiter.notify_all();
}
}
}
bool zeroWait(unsigned int timeout_ms) {
std::unique_lock<std::mutex> _(lock);
return waiter.wait_for(_,std::chrono::milliseconds(timeout_ms), [=]{return counter == 0;});
}
void zeroWait() {
std::unique_lock<std::mutex> _(lock);
waiter.wait(_,[=]{return counter == 0;});
}
unsigned int getCounter() const {
return counter;
}
void setCounter(unsigned int counter) {
std::unique_lock<std::mutex> _(lock);
this->counter = counter;
if (counter == 0) {
waiter.notify_all();
}
}
protected:
std::mutex lock;
std::condition_variable waiter;
unsigned int counter = 0;
};
-
V metodě getCounter není korektní takhle přistupovat k proměnné counter bez mutexu. Mutex musí být pro zápis i čtení, jinak je tam race condition.
-
V metodě getCounter není korektní takhle přistupovat k proměnné counter bez mutexu. Mutex musí být pro zápis i čtení, jinak je tam race condition.
Já bych to ještě doplnil, že samotná funkce getCounter je velice sporná, pokud by měla sloužit k čemukoliv jinému než nějaké statistice.
-
V metodě getCounter není korektní takhle přistupovat k proměnné counter bez mutexu. Mutex musí být pro zápis i čtení, jinak je tam race condition.
Já bych to ještě doplnil, že samotná funkce getCounter je velice sporná, pokud by měla sloužit k čemukoliv jinému než nějaké statistice.
Ta funkce má smysl, pokud ji používá jediné vlákno, které zároveň s counterem manipuluje. Tam pak mutex není potřeba, protože jen to jedno vlákno ho čte a mění. Zároveň v situaci, kdy těch vláken mám víc, pak ta funkce smysl nemá a volat ji taky smysl nemá. Proto je tam mutex v zásadě zbytečný.
-
jsou v C++ ve vychozim stavu thread safe?
-
jsou v C++ ve vychozim stavu thread safe?
chybí mi tam "jsou atributy objektů"... (sorry, nejde editovat ani vlastní příspěvek)
-
jsou v C++ ve vychozim stavu thread safe?
Jestli C++ jsou atributy thread safe? Odpověď zní NE. A ani to není žádoucí protože zajištění thread safety je výkonově drahé a obecně se snažíme jakékoliv interakce mezi thready minimalizovat aby se to muselo řešit na co nejméně mistech.
V tomto konkrétním případě jde o to že atribut counter není thread safe ale taky jeho čtení v okamžiku používání vícero vlákny je samo sebou nesmyslné protože může vracet stará data a teoreticky může dojít k poškození údaje při čtení a zároveň zápisu jiným vláknem. (Prakticky se to ale při čtení intu nestane). Nicméně se nepředpokládá nějaké praktické využití v tomto režimu je to spíš kvůli možnosti výpisu vnitřního stavu pro účely nějakého ladění a logovánI
-
Vola sa to Barrier alebo WaitGroup.
Skoro urcite to riesis zle. Na cakanie na dokoncenie operacie (alebo operacii) je lepsi promise/future. S nimi nemusis riesit take tie problemy ako "pripocital som?", "nie je tam race condition?" a podobne. Ked sa ti podari deadlock, tak byva deterministicky. Caka to prave na hodnoty, ktore chces pouzit.
-
Hele, nechci te nak moc presvedcovat, protoze neznam uplne situaci, ale uz to tu nekdo rikal. Nestaci na to opravdu std::atomic ?
Protoze:
1) vic lightly operaci asi nesezenes. Protoze nakonec nakonec stejne budes potrebovat "thread-safe" counter.
2) ruzne typy futuru muzou byt fakt hodne overhead, ktery nepotrebujes resit.
3) ano, samozrejme se to musi nejak inicializovat, ale stejne, pokud se tvuj thread pusti drive/soucasne s ostatnima threadama, tak stejne tezko muzes urcit, jestli uz dobehly nebo ne jinak, nez ze nekde zvenku reknes, co uz melo dobehnout. Ano promise/future ... ale imho atomic counter bude fakt lightweight mnohem vic a muze stacit. Ale fakt neznam cely problem, takze tezko rict...
4) Nepotrebujes nakonec vlastne jen atomic-- ?
-
Vola sa to Barrier alebo WaitGroup.
Skoro urcite to riesis zle. Na cakanie na dokoncenie operacie (alebo operacii) je lepsi promise/future. S nimi nemusis riesit take tie problemy ako "pripocital som?", "nie je tam race condition?" a podobne. Ked sa ti podari deadlock, tak byva deterministicky. Caka to prave na hodnoty, ktore chces pouzit.
Ne sorry, "pripocital som?" fakt je ukazuje na lehce neschopné programování. Tohle fakt nastat nemůže. Už třeba proto, že bežící task může provádět increment/decrement přes RAII, takže je to i exception safe. Při vzniku tasku zavolá inc, při dokončení tasku nebo jeho destrukci zavolá dec. Race condition tam určitě není.
Stejným způsobem třeba podobný problém nenastane při refcountingu, což je podobný problém, akorát tam jde o zničení objektu když refcount klesne na nulu. Tady jde o odblokování vlákna.
Hele, nechci te nak moc presvedcovat, protoze neznam uplne situaci, ale uz to tu nekdo rikal. Nestaci na to opravdu std::atomic ?
No, šlo by tam mít atomic counter, ale funkci wait() mi atomic neudělá, leda přes nějaký spinlock. Na zastavení vlákna potřebuju mutex a condvar. No a když už tam mám mutex, tak ten atomic je už zbytečný. Možná ještě rychlejší by to bylo, kdyby counter byl atomic, tim bych se vyhnul zamykání při inc/dec.
Ale já jsem chtěl vědět, jestli se tohle někde nepoužívá, že bych uspůsobil rozhraní a název abych to měl standardní