QL.túra

Kulturális smörgåsbord Esterházytól Wass Albertig, a gumicsizmától az iPad-ig, a Teletabiktól Sexpírig, a makrofágtól a mikrokontrollerig, miazmás...

Címkék

2000 (20) 2001 (6) 2002 (16) 2003 (164) 2004 (61) 2005 (40) 2006 (31) 2007 (28) 2008 (33) 2009 (175) 2010 (188) 2011 (201) 2012 (86) 2013 (40) 2014 (36) 2015 (26) 2016 (10) adáshiba (91) android (1) animáció (93) cygwin (3) film (410) gezarol (13) hájtek (159) hangoskönyv (32) ipad (17) klip (12) könyv (191) linux (29) színház (169) vers (17) windows (37) zene (111) Címkefelhő

+jegyzések

Most ...

... múlok .osan

bmi_tiny.png


... hallgatom
Szabó Magda: Régimódi történet
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSqTmZEqlCRFgojyt52Q2n_qiMTyVlt-zJu-DpbNKVY6OQbBh4u


... olvasom
Alexander Steele (szerk.): Kezdő írók kézikönyve


... (Kik ezek? Kik ezek az embek? Kik ezek?)
profile for TrueY on Stack Exchange, a network of free, community-driven Q&A sites
free counters

[Hájtek] lock-olás bash-ben

2011.02.11. 12:00 | TrueY | Szólj hozzá!

Címkék: linux 2011 hájtek

Az erőforrások kisajátítása minden programnyelven problémát jelent. Ilyen-olyan megoldások vannak rá. Vannak, ahol csak indirekt módon valósítható meg. Vagy maga a nyelv nem támogatja, vagy az OS (sem). A probléma lényege, hogyan lehet biztos egy bash szkript, hogy ő egyedül művel valamit a rendszerben. A kérdés viszonylag egyszerű, de valóban jó megoldást nem találtam rá. Bash-ban csak kooperatív megoldást tudtam összetákolni.

A legegyszerűbb (problémás) megoldás:

if [ ! -f "$lock_file" ]; then
    >"$lockfile"
    #Kritikus_resz
    rm -f "$lockfile"
fi
Ezzel sajna több probléma is vagyon:

  • Ha elhal a szkript a kritikus részben, akkor a lock_file ott marad, tehát addig nem fogjuk tudni futtatni az alkalmazást, amíg valaki észre nem veszi, hogy az alkalmazás már halott és kézzel le nem törli a lock file-t. Ezzel azt lehet kezdeni, hogy a lock file-ba betesszük a procesz PID-jét és a mások program "kill -0 <PID>" utasítással meg tudja nézni, hogy fut-e. Ennél kicsit pontosabb, ha a /proc/<PID>/cmdline-t vizsgáljuk. Már ha van /proc filesystem. Persze lehet "ps -ef|grep...|awk....|wc..." kígyókat is alkalmazni, de tök felesleges! Akinél pedig meglátom, hogy grep, sed mellett awk-t is használ, ráverek a kezére! Egy awk hívással lekezelhető az egész! Hasonló sors vár a "cat file|grep valami" használókra is!
  • "Race condition" helyzet van, azaz tegyük fel, hogy egyszerre indul két szkript. Mindegyik azt látja, hogy nincs lock_file és mind a kettő megcsinálja a lock_file-t és lefuttatja a kritikus részt. Pont ezt szeretnénk elkerülni.

Az első problémát a fontos események csapdázásával (trap) oldhatjuk meg, a másikat pedig valamilyen olyan hívással, ami egyszerre csinál valamit és elbukik, ha nem tudja már megcsinálni (azaz atomi művelet. Atomi a démokritoszi értelemben! És ne jöjjön senki a kvarkokkal!). Ezekre példa: mv file file2;, ln file file2;, ln -s file file2, (set -o noclobber; >lock_file), mkfifo pipe. Ha nem szeretnénk semmilyen más infót beleírni a lock file-ba (mondjuk a PID-et, ami néha hasznos lehet), akkor én az ln-t (hard link) használnám, mert akkor csak egy bejegyzés keletkezik a directory-ba, de egyéb terület nem kell, hogy lefoglalódjon és megspórolunk pár lemezműveletet is (persze fontos, hogy a link ugyanarra a partícióra kerüljön, mint az eredeti linkelendő file).

lock="$0.lock"

if ln "$0" "$lock"; then
    trap 'rm -f "$pipe"; exit $?;' EXIT

    kritikus_dolgok

    rm -f "$lock"
    trap - EXIT
else
    echo "Cannot get locked"
fi
Néhol az INT és TERM-et is trap-polják, de tesztjeim szerint Cygwin és Linux alatt is mindig jól lefut az EXIT (pl. Ctrl+C, kill -HUP, kill -TERM). Még akkor is, ha a szülő bash-t lövöm le. Az ln kimenete a /dev/null-ba irányítandó, ha nem szeretnénk a hibaüzeneteket látni.

Persze ez sem tökéletes, mert az ln és a trap között még marad egy kis esély, hogy mondjuk egy megszakítás beszaladjon és akkor a lock fent marad, mert a trap nem hajtódik végre... Ha a trap-et korábban csináljuk, mint az if-fet és a második példány vagyunk, akkor egy jól irányzott ctrl+C-vel leszedhetjük a lock file-t az else ágban, mielőtt a trap-et leállíthatnánk. Szóval valami olyan kellene, ami a trap-et és a lock-ot egyszerre állítja. Ilyet nem találtam...

Esetleg ezt lehetne még, de szerintem ez sem nevezhető "atomi" lépésnek, inkább csak kódfésülés:

if ln "$0" "$lock" && trap 'rm -f "$lock"; exit $?;' EXIT; then
    kritikus_dolgok
    rm -f "$lock"
    trap - EXIT
fi


Előfordul, hogy a másodpéldányoknak kommunikálniuk kell az első példánnyal. Ekkor a lock file lehet egy pipe (FIFO) file is, amit "mknod pipe p", vagy "mkfifo pipe" paranccsal hozhatunk létre. Sajnos cygwin alatt egyes üzenetek elvesznek, ha fifo-ba írunk. Ezt nem értem, hogy miért van... Sok helyen azt olvastam, hogy cygwin alatt nem megy rendesen a fifo. Akkor sima file-ra váltok, hogy Linux és Cygwin alatt is menjen a dolog:

prog=${0##*/} # get basename
queue="/tmp/$prog.queue"
echo "PID: $$, PPID: $PPID"

if (set -o noclobber; >"$queue" ) 2>/dev/null && trap 'rm -f "$queue"; exit $?;' EXIT; then
    # Kritikus resz
    echo **EN** $$ $(date) BBB CCC DDD >"$queue"
    exec 10<"$queue" # 3 elegendo lenne 10 helyett

    while read -a a -u 10; do
        echo Olvasva $(date) === ${a[*]}
        sleep 5; # Valami fontos
    done

    exit 0
else
    #Nem kritikus
    echo $$ $(date) BBB CCC DDD >>"$queue"
fi

Persze a cső nevébe tehetünk felhasználó nevet, egyedi ID-t (pl. PID), vagy bármi mást, ha többen is használnák. Meg persze az eredeti szkriptet is hard linkelhetjük több néven, ami szintén egy szép unix-os megoldás...

Legyünk kritikusak minden nap!

A bejegyzés trackback címe:

https://qltura.blog.hu/api/trackback/id/tr532512586

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása