Сообщение Re: Временный блокировщик от 06.02.2024 13:26
Изменено 06.02.2024 18:24 Кодт
Re: Временный блокировщик
Здравствуйте, Marty, Вы писали:
M>Где-то в каком-то потоке периодически что-то производится, какие-то действия. Иногда надо временно запретить их производить.
M>В других потоках, или в том же потоке, можно запрещать, рекурсивно, главное, разлочить столько же раз, сколько и залочил.
Если не вдаваться в подробности, то правда ли, что апи получается такой? Назовём эту штуку "дверь". Потому что поток проходит через неё и дальше занимается своими делами.
Надо заметить, что поток может запереть сам себя:
и в этом случае ему нужна внешняя помощь — какой-то другой поток должен отпереть эту дверь
M>Что-то городить с какими-то примитивами синхронизации не вижу смысла, ну, может я ошибаюсь.
Примитивы синхронизации стоят дёшево, пока не попадают на блокировку.
Но если очень хочется упороться по лок-фри и написать своё, заведомо userspace, то ради бога.
Семафоры и мьютексы, будучи симметричными инструментами, тут не подойдут. (Не, конечно, на паре семафоров можно построить абсолютно все производные примитивы).
А вот на кондеях такое делается элементарно
M>Где-то в каком-то потоке периодически что-то производится, какие-то действия. Иногда надо временно запретить их производить.
M>В других потоках, или в том же потоке, можно запрещать, рекурсивно, главное, разлочить столько же раз, сколько и залочил.
Если не вдаваться в подробности, то правда ли, что апи получается такой? Назовём эту штуку "дверь". Потому что поток проходит через неё и дальше занимается своими делами.
struct Door {
int level = 0;
bool is_open() const { return level > 0; }
// апи управляющей стороны (не ждёт) (меняет состояние двери)
void open() { ++level; }
void close() { --level; }
// апи управляемой стороны (не меняет состояние двери)
bool try_pass() const { return is_open(); } // не ждёт
bool pass(auto timeout) const { WAIT(timeout, is_open); return is_open(); }
void pass() const { WAIT(is_open); }
}
Надо заметить, что поток может запереть сам себя:
void foo(Door& door) {
door.close();
.....
door.pass();
.....
}
и в этом случае ему нужна внешняя помощь — какой-то другой поток должен отпереть эту дверь
M>Что-то городить с какими-то примитивами синхронизации не вижу смысла, ну, может я ошибаюсь.
Примитивы синхронизации стоят дёшево, пока не попадают на блокировку.
Но если очень хочется упороться по лок-фри и написать своё, заведомо userspace, то ради бога.
Семафоры и мьютексы, будучи симметричными инструментами, тут не подойдут. (Не, конечно, на паре семафоров можно построить абсолютно все производные примитивы).
А вот на кондеях такое делается элементарно
class Door {
int level = 0;
mutable std::mutex guard;
std::conditional_variable cv;
bool is_open() const {
return level > 0;
}
auto is_open_fun() const {
return [this]() { return is_open();
}
public:
void open() {
std::unique_lock lock(guard);
++level; // спасибо vopl за фикс недочепятки
if (is_open()) cv.notify_all();
}
void close() {
std::unique_lock lock(guard);
--level;
}
bool try_pass() const {
std::unique_lock lock(guard);
return is_open();
}
bool pass(auto timeout) const {
std::unique_lock lock(guard);
return cv.wait_for(lock, timeout, is_open_fun());
}
void pass() const {
std::unique_lock lock(guard);
cv.wait(lock, is_open_fun());
}
};
Re: Временный блокировщик
Здравствуйте, Marty, Вы писали:
M>Где-то в каком-то потоке периодически что-то производится, какие-то действия. Иногда надо временно запретить их производить.
M>В других потоках, или в том же потоке, можно запрещать, рекурсивно, главное, разлочить столько же раз, сколько и залочил.
Если не вдаваться в подробности, то правда ли, что апи получается такой? Назовём эту штуку "дверь". Потому что поток проходит через неё и дальше занимается своими делами.
Надо заметить, что поток может запереть сам себя:
и в этом случае ему нужна внешняя помощь — какой-то другой поток должен отпереть эту дверь
M>Что-то городить с какими-то примитивами синхронизации не вижу смысла, ну, может я ошибаюсь.
Примитивы синхронизации стоят дёшево, пока не попадают на блокировку.
Но если очень хочется упороться по лок-фри и написать своё, заведомо userspace, то ради бога.
Семафоры и мьютексы, будучи симметричными инструментами, тут не подойдут. (Не, конечно, на паре семафоров можно построить абсолютно все производные примитивы).
А вот на кондеях такое делается элементарно
M>Где-то в каком-то потоке периодически что-то производится, какие-то действия. Иногда надо временно запретить их производить.
M>В других потоках, или в том же потоке, можно запрещать, рекурсивно, главное, разлочить столько же раз, сколько и залочил.
Если не вдаваться в подробности, то правда ли, что апи получается такой? Назовём эту штуку "дверь". Потому что поток проходит через неё и дальше занимается своими делами.
struct Door {
int level = 0;
bool is_open() const { return level > 0; }
// апи управляющей стороны (не ждёт) (меняет состояние двери)
void open() { ++level; }
void close() { --level; }
// апи управляемой стороны (не меняет состояние двери)
bool try_pass() const { return is_open(); } // не ждёт
bool pass(auto timeout) const { WAIT(timeout, is_open); return is_open(); }
void pass() const { WAIT(is_open); }
}
Надо заметить, что поток может запереть сам себя:
void foo(Door& door) {
door.close();
.....
door.pass();
.....
}
и в этом случае ему нужна внешняя помощь — какой-то другой поток должен отпереть эту дверь
M>Что-то городить с какими-то примитивами синхронизации не вижу смысла, ну, может я ошибаюсь.
Примитивы синхронизации стоят дёшево, пока не попадают на блокировку.
Но если очень хочется упороться по лок-фри и написать своё, заведомо userspace, то ради бога.
Семафоры и мьютексы, будучи симметричными инструментами, тут не подойдут. (Не, конечно, на паре семафоров можно построить абсолютно все производные примитивы).
А вот на кондеях такое делается элементарно
class Door {
int level = 0;
mutable std::mutex guard;
std::conditional_variable cv;
bool is_open() const {
return level > 0;
}
auto is_open_fun() const {
return [this]() { return is_open(); };
}
public:
void open() {
std::unique_lock lock(guard);
++level; // спасибо vopl за фикс недочепятки
if (is_open()) cv.notify_all();
}
void close() {
std::unique_lock lock(guard);
--level;
}
bool try_pass() const {
std::unique_lock lock(guard);
return is_open();
}
bool pass(auto timeout) const {
std::unique_lock lock(guard);
return cv.wait_for(lock, timeout, is_open_fun());
}
void pass() const {
std::unique_lock lock(guard);
cv.wait(lock, is_open_fun());
}
};