真线程:不锁会丢,锁了不丢

👁️ 2 人浏览 💬 0 人评论 ❤️ 添加收藏

(每道题开头都有同一段:上面的模拟器。判题机要确定的答案,所以本条用「调度表」代替真线程的运气。)

(这一节还带着真线程版:Counter 的 inc 是读-睡-写(conc_02 的写法),SafeCounterwith lock 包住它;hammer(counter, workers, times) 开几条线程各加 times 次,交回最终的 n。真线程的结果不确定,题里只比大小。)

两条线程各加 30 次,一次不锁一次锁,只比大小:

def inc_steps(k=1):
    return [("read",), ("add", k), ("write",)]


def check_act_steps(need=1):
    return [("read",), ("check", need), ("add", -need), ("write",)]


def run_schedule(threads, schedule, start=0):
    """threads: 每条线程是「步」的列表;schedule: 线程编号的序列,每个编号出现一次就走一步。
    共享变量 n;每条线程有自己的寄存器 reg。交回 (最终 n, 记录列表)。"""
    n = start
    pc = [0] * len(threads)
    reg = [0] * len(threads)
    log = []
    for t in schedule:
        if pc[t] >= len(threads[t]):
            continue
        step = threads[t][pc[t]]
        pc[t] += 1
        n, reg[t], note, go_on = do_step(step, n, reg[t])
        log.append("T" + str(t) + ":" + note)
        if not go_on:
            pc[t] = len(threads[t])      # 检查没过:这条线程后面的步全部跳过
    return n, log


def do_step(step, n, r):
    if step[0] == "read":
        return n, n, "read " + str(n), True
    if step[0] == "add":
        return n, r + step[1], "add→" + str(r + step[1]), True
    if step[0] == "write":
        return r, r, "write " + str(r), True
    if step[0] == "check":
        ok = r >= step[1]
        return n, r, "check " + str(r) + (">=" if ok else "<") + str(step[1]), ok
    if step[0] == "atomic":
        notes = []
        ok = True
        for s in step[1]:
            n, r, note, ok = do_step(s, n, r)
            notes.append(note)
            if not ok:
                break
        return n, r, "atomic(" + ",".join(notes) + ")", ok
    raise ValueError(step[0])


def all_schedules(a, b):
    """两条线程(a 步和 b 步)的全部交错:每个交错是一串 0/1。"""
    if a == 0:
        return [[1] * b]
    if b == 0:
        return [[0] * a]
    return [[0] + s for s in all_schedules(a - 1, b)] + [[1] + s for s in all_schedules(a, b - 1)]


def outcomes(threads, start=0):
    counts = {}
    for s in all_schedules(len(threads[0]), len(threads[1])):
        n, _ = run_schedule(threads, s, start)
        counts[n] = counts.get(n, 0) + 1
    return counts


def locked(steps):
    return [("atomic", steps)]


import threading
import time


class Counter:
    def __init__(self):
        self.n = 0

    def inc(self):
        tmp = self.n
        time.sleep(0.001)
        self.n = tmp + 1


class SafeCounter(Counter):
    def __init__(self):
        super().__init__()
        self.lock = threading.Lock()

    def inc(self):
        with self.lock:
            super().inc()


def hammer(counter, workers=2, times=30):
    def work():
        for _ in range(times):
            counter.inc()
    ts = [threading.Thread(target=work) for _ in range(workers)]
    for t in ts:
        t.start()
    for t in ts:
        t.join()
    return counter.n


a = hammer(Counter(), 2, 30)
b = hammer(SafeCounter(), 2, 30)
print(str(a < 60) + "/" + str(b == 60) + "/" + str(a <= b))
提交你的答案
请登录后提交答案。
去登录
代码编辑器
Ctrl + Enter 运行
本次输入:
输出:

                        
👩‍🏫
AI
💬 题目评论

全部评论