КДП/К2 2022

Извор: SI Wiki
Пређи на навигацију Пређи на претрагу

Други колоквијум 2022. године одржан је 15. маја.

1. задатак

Поставка

Решити проблем Читалаца и писаца (Readers/Writers) користећи мониторе са дисциплином Signal and Continue. Проблем решити користећи технику прослеђивања услова (Passing the Condition). Монитор треба да поседује 4 методе: lockShared() — желим да читам, lockExclusive() — желим да пишем, unlock() — завршавам, и upgradeLock() — са читања прелазим на писање.

Решење

class ReadersWriters {
    private int readers = 0;
    private int writers = 0;
    private int ticket = 1;
    private Condition okToRead = new Condition();
    private Condition okToWrite = new Condition();
    public synchronized void lockShared() {
        if (writers == 0 && okToWrite.empty()) {
            ++readers;
        } else {
            okToRead.wait(ticket++);
        }
    }
    public synchronized void lockExclusive() {
        if (readers == 0 && writers == 0) {
            ++writers;
        } else {
            okToWrite.wait(ticket++);
        }
    }
    public synchronized void unlock() {
        if (readers > 0) {
            if (--readers == 0 && okToWrite.queue()) {
                writers = 1;
                okToWrite.signal();
            }
        } else {
            boolean readersNext = okToRead.queue() && (okToWrite.empty() || okToRead.minrank() < okToWrite.minrank());
            boolean writersNext = okToWrite.queue() && (okToRead.empty() || okToWrite.minrank() < okToRead.minrank());
            if (readersNext) {
                while (okToRead.queue() && okToRead.minrank() < okToWrite.minrank()) {
                    ++readers;
                    okToRead.signal();
                }
            } else if (writersNext) {
                okToWrite.signal();
            } else {
                writers = 0;
            }
        }
    }
    public synchronized void upgradeLock() {
        if (readers == 1) {
            // Ако је само један читалац, конвертуј га у писца
            readers = 0;
            writers = 1;
        } else {
            // У супротном, мораће да сачека остале читаоце и писце како би постао писац
            unlock();
            lockExclusive();
        }
    }
}

2. задатак

Поставка

На обали реке се налази чамац који може да прими тачно десет путника. Чамац могу да користе мушкарци, жене и деца. Чамац може да исплови само ако се у њему налази тачно онолико путника колики му је капацитет, али само под условом да се у чамцу налазе бар два мушкарца. Деца не смеју ући у чамац уколико се у њему не налазе бар једна одрасла особа и по завршетку вожње у чамцу не смеју да остану само деца. Сматрати да ће се[sic] чамац након искрцавања свих путника одмах бити спреман да прими наредну групу путника. Користећи регионе написати програм који решава овај проблем.

Решење

struct Boat {
    // Број мушкараца, жена и деце
    int men = 0;
    int women = 0;
    int children = 0;
    // Да ли је вожња готова (да ли је у току искрцавање)
    bool done;
    // Помоћне методе
    int total() {
        return men + women + children;
    }
    int adults() {
        return men + women;
    }
};
Boat boat;

void boatP() {
    while (true) {
        region (boat) {
            boat.done = false;
            await (boat.total() == 10 && boat.men >= 2);
        }
        // Вожња
        region (boat) {
            boat.done = true;
            await (boat.total() == 0);
        }
    }
}

void man() {
    while (true) {
        region (boat) {
            await (!boat.done);
            if (boat.total() < 10) {
                ++boat.men;
                break;
            } else {
                // Нисмо се укрцали, чекамо да се заврши вожња па поново
                await (boat.done);
            }
        }
    }
    // Укрцани смо
    region (boat) {
        await (boat.done);
        // Ако смо последњи одрасли, чекамо да сва деца изађу
        if (boat.adults() == 1 && boat.children > 0) {
            await (boat.children == 0);
        }
        --boat.men;
    }
}

void woman() {
    while (true) {
        region (boat) {
            await (!boat.done);
            if (boat.total() < 10 && boat.total() - boat.men <= 7) {
                ++boat.women;
                break;
            } else {
                // Нисмо се укрцали, чекамо да се заврши вожња па поново
                await (boat.done);
            }
        }
    }
    // Укрцани смо
    region (boat) {
        await (boat.done);
        // Ако смо последњи одрасли, чекамо да сва деца изађу
        if (boat.adults() == 1 && boat.children > 0) {
            await (boat.children == 0);
        }
        --boat.women;
    }
}

void child() {
    while (true) {
        region (boat) {
            await (!boat.done);
            if (boat.total() < 10 && boat.total() - boat.men <= 7 && boat.adults() > 0) {
                ++boat.children;
                break;
            } else {
                // Нисмо се укрцали, чекамо да се заврши вожња па поново
                await (boat.done);
            }
        }
    }
    // Укрцани смо
    region (boat) {
        await (boat.done);
        --boat.children;
    }
}