A Pike programozási nyelv

Párhuzamosság



A Pike szálkezelése

Bármely józan ésszel megáldott programozó tapasztalhatja, hogy a Pike szálkezeléshez való viszonya egyszerű és ötletes. Minden olyan rendszeren elérhető amely támogatja az UNIX-ot, POSIX-ot, vagy a Windows szálkezelést. a Thread modul egy szabványos könyvtár, mely a többszálú programozáshoz nyújt teljes eszköztárat. Alapból, egy szál a Thread.Thread egy osztályának új példányosításánál kezdi el rögtön müködését a paraméterül kapott függvény és paraméterezése szerint.

void say_hello(string name) { write("Hello, " + name + ".\n"); } int main() { Thread.Thread thread; thread = Thread.Thread(say_hello, "Jeff"); return -1; // return -1 so execution does not terminate }

A Pike interpretere teljesen szálbiztos. Minden végrehajtást a globális interpreter zár véd, hasonlóan, mint a Python-ban. A különbség az, hogy a Pike lockolása sokkal finomabb és sokkal gyakrabban engedi tovább a futást.

Thread.Mutex és Thread.MutexKey

A mutexek elengedhetetlenek, hogy megvédjék a kritikus szakaszokat, melyeket atomian kell lefuttatni. Az interpreter zárnak köszönhetően két szál soha nem fogja elérni ugyanazt a változót egyidőben. Azonban, ha ezz a változót módosítjuk vagy többször is olvassuk egy szálon belül, akkor mutex-ot kell használnunk a változó megőrzésére.

void func() { Thread.Mutex m = Thread.Mutex(); // create a mutex Thread.MutexKey k = m->lock(); // acquire the lock ... // do stuff ... // do more stuff return; }

Észrevehetjük, hogy a mutexet nem szabadítottuk fel. Amint a (Mutex->lock() által visszaadott) MutexKey kilép a hatókörből, a mutex automatikusan felszabadul. Ez azt is jelenti, hogy a művelet már úgy is szinkronizálva lesz, ha csak a függvény elején kérjük a zárt.

Thread.Condition

Az állapot változókat arra használjuk, hogy szinkronizáljuk velük a szálak közötti kommunikációt. Egy szál, mely épp az erőforrást birtokolja egy állapot változót is tartalmaz, míg a többi szál épp arra vár, hogy ez a változó szignált küldjön. A vezérlést birtokló szál választhat, hogy csak egy (MutexKey-t megadva), vagy az összes várakozó szálnak küldjön szignált egyszerre. Épp ezért a várakozó szálaknak kötelező MutexKey-jel rendelkeznie, hogy garantálhassuk a szinkronizációt.

Thread.Local

Szálhoz tartozó adatot hozhatunk létre vele.

string thread_fn() { Thread.Local data = Thread.Local(); data->set("foo"); return data->get(); }

Thread.Queue

A sor egy FIFO konténer, mely bővíthető, tehát ha új elemet szúrunk bele, sosem fog blokkolódni. Másik érdekes művelet a read_array, amely annyi értéket olvas be, amennyi a sorban épp van, amennyit csak tud. Ez rendkívül hasznos, ugyanis egy munka eredményét sokkal gyorsabban beolvashatjuk, anélkül hogy a blokkolásokra várnánk, az aktív sorok sokkal hatékonyabbá válnak.

void consumer(Thread.Queue q) { while (1) { string value = q->read(); // block until value available do_something_with(value); } }