多线程简单死锁漏洞逃避检测

Multithreaded simple deadlock bug evading detection

我正在 class 学习 multithreading,所以请不要实施解决方案;不过,我们还是很感激改进建议。

10,000 英尺概览:main 接受 3 个参数(线程、资源和运行时长度)。每个线程等待一个随机时间,然后决定随机访问共享 resources/critical 部分,完成后放弃资源。重复提供的运行时长度,然后退出所有线程。

基于卡丁车赛道用户轮流骑行和游走的问题

我创建了一个死锁,但我不知道那是怎么回事。

Sleeper只是分配线程等待一段时间。

骑手class:

public void run() {
        while (!coord.exit) {
            System.out.format("Rider %d is gone walkabout%n", ID);
            Sleeper.walkAround(ID);
            System.out.format("Rider %d is in line%n", ID);
            try {
            carID = coord.getInLine();
            System.out.format("Rider %d is riding car %d%n", ID, carID);
            Sleeper.rideTime(ID);
            coord.returnCar(carID);
            } catch (InterruptedException ie) {System.out.println("Thread " + ID + " was interrupted.");}
        }
    }

协调员class是肉所在:

public class Coordinator {

    Rider[] riderArr;
    Semaphore mutex = new Semaphore(1);
    Semaphore cars;
    LinkedList<Integer> carLine;
    volatile static boolean exit = false;

    public synchronized int getInLine() throws InterruptedException {
        cars.acquire();
        mutex.acquire();
        int carid = carLine.removeFirst();
        mutex.release();
        return carid;
    }

    public synchronized void returnCar(int carID) throws InterruptedException {
        mutex.acquire();
        carLine.add(carID);
        mutex.release();
        cars.release();
    }

    public Coordinator(int cars, int riders) {
        riderArr = new Rider[riders];
        for (int i = 0; i < riders; i++) {
            riderArr[i] = new Rider(this, i + 1);
        }
        carLine = new LinkedList<Integer>();
        for (int i = 0; i < cars; i++) {
            carLine.add(i + 1);
        }
        this.cars = new Semaphore(cars);
    }

    public static void main(String[] args) throws NumberFormatException, InterruptedException {
        Coordinator coord = new Coordinator(Integer.parseInt(args[0]),
                Integer.parseInt(args[1]));
        for (int i = 0; i < Integer.parseInt(args[1]); i++) {
            coord.riderArr[i].start();
        }
        Thread.sleep(1000 * Integer.parseInt(args[2]));
        exit = true;
        for (int i = 0; i < Integer.parseInt(args[1]); i++) {
            coord.riderArr[i].join();
        }
        System.exit(0);
    }
}

这是死锁会话的控制台输出:

Rider 2 is gone walkabout
Rider 2 is walking around for  4 seconds
Rider 1 is gone walkabout
Rider 1 is walking around for  1 seconds
Rider 1 is in line
Rider 1 is riding car 1
Rider 1 is riding for 3 seconds
Rider 2 is in line

这是一个死锁场景:

  • N 个线程获取 cars
  • 中的所有 N Semaphore 个令牌
  • 线程 X 进入 getInLine 并等待 cars#acquire

因为getInLinesynchronized并且X有锁,所以N个线程中的任何一个都没有办法return一个token。这是因为 returnCar 方法也是 synchronized


实现目标的更好方法是将 carLine#removeFirstcarLine#add 放在它们自己的 synchronized 方法中,并从其他两个方法中删除 synchronized :

public synchronized int removeCar(){
    return carLine.removeFirst();
}

public synchronized void addCar(int car){
    carLine.add(car);
}

这也消除了您对 mutex 对象的需求。您改为使用 Coordinator 对象本身作为互斥体。这也意味着在信号量上等待 acquire 不会阻止您 returning 它的令牌