雑学1473612 views
中学英語811710 views
高校倫理1440106 views
中学理科1630641 views
ヒストリア290598 views
世界の国564520 views
Computer368106 views
数学講師2886227 views
高校日本史190571 views
LaTeX962153 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

Python の RLock で再入可能なロックを使う

RLock(Reentrant Lock、再入可能ロック)は、同じスレッドから複数回取得できるロックです。通常の Lock では同じスレッドが2回ロックを取得しようとするとデッドロックになりますが、RLock ではそれを避けられます。

Lock と RLock の違い

通常の Lock は、同じスレッドであっても2回取得しようとするとブロックされます。

import threading

lock = threading.Lock()

def outer():
    with lock:
        print("outer")
        inner()  # ここでデッドロック!

def inner():
    with lock:  # 同じスレッドでも再取得できない
        print("inner")

# outer()  # これを実行するとデッドロック

RLock を使えば、同じスレッドから何度でもロックを取得できます。

import threading

rlock = threading.RLock()

def outer():
    with rlock:
        print("outer")
        inner()

def inner():
    with rlock:  # 同じスレッドなので取得できる
        print("inner")

outer()
# outer
# inner

RLock の動作

Lock

同じスレッドでも2回目の acquire でブロックされる。

RLock

同じスレッドなら何度でも acquire できる。acquire と同じ回数だけ release が必要。

RLock は内部でカウンターを持っており、acquire() の回数と同じだけ release() を呼ぶ必要があります。

import threading

rlock = threading.RLock()

rlock.acquire()
print("1回目取得")
rlock.acquire()
print("2回目取得")
rlock.acquire()
print("3回目取得")

rlock.release()
print("1回目解放")
rlock.release()
print("2回目解放")
rlock.release()
print("3回目解放(完全に解放)")

実用例:再帰的な処理

再帰的にロックを必要とする処理で RLock が役立ちます。

import threading

class TreeNode:
    def __init__(self, value):
        self.value = value
        self.children = []
        self._lock = threading.RLock()
    
    def add_child(self, node):
        with self._lock:
            self.children.append(node)
    
    def total(self):
        with self._lock:
            total = self.value
            for child in self.children:
                total += child.total()  # 再帰的に呼び出し
            return total

root = TreeNode(10)
root.add_child(TreeNode(5))
root.add_child(TreeNode(3))
print(root.total())  # 18

実用例:メソッド間でロックを共有

複数のメソッドが同じロックを使い、互いに呼び出し合う場合に便利です。

import threading

class BankAccount:
    def __init__(self, balance):
        self.balance = balance
        self._lock = threading.RLock()
    
    def deposit(self, amount):
        with self._lock:
            self.balance += amount
            print(f"入金: {amount}, 残高: {self.balance}")
    
    def withdraw(self, amount):
        with self._lock:
            if self.balance >= amount:
                self.balance -= amount
                print(f"出金: {amount}, 残高: {self.balance}")
                return True
            return False
    
    def transfer(self, other, amount):
        with self._lock:
            if self.withdraw(amount):  # withdraw も同じロックを使う
                other.deposit(amount)

account1 = BankAccount(1000)
account2 = BankAccount(500)
account1.transfer(account2, 200)

いつ RLock を使うべきか

RLock が必要なケース

同じロックで保護されたメソッドを再帰的に呼び出す場合。メソッドが他のロック保護されたメソッドを呼ぶ場合。

Lock で十分なケース

単純な排他制御。再入の必要がない場合。パフォーマンスを重視する場合(Lock の方がわずかに高速)。

RLock は便利ですが、必要ない場合は通常の Lock を使う方がシンプルです。デッドロックのリスクがある場合にのみ RLock を検討しましょう。