Главная страница Случайная страница Разделы сайта АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
💸 Как сделать бизнес проще, а карман толще?
Тот, кто работает в сфере услуг, знает — без ведения записи клиентов никуда. Мало того, что нужно видеть свое раписание, но и напоминать клиентам о визитах тоже.
Проблема в том, что средняя цена по рынку за такой сервис — 800 руб/мес или почти 15 000 руб за год. И это минимальный функционал.
Нашли самый бюджетный и оптимальный вариант: сервис VisitTime.⚡️ Для новых пользователей первый месяц бесплатно. А далее 290 руб/мес, это в 3 раза дешевле аналогов. За эту цену доступен весь функционал: напоминание о визитах, чаевые, предоплаты, общение с клиентами, переносы записей и так далее. ✅ Уйма гибких настроек, которые помогут вам зарабатывать больше и забыть про чувство «что-то мне нужно было сделать». Сомневаетесь? нажмите на текст, запустите чат-бота и убедитесь во всем сами! Void f()
{ //... // создаемблокировку, но не захватываем мьютекс std:: unique_lock lck(m, std:: defer_lock); //... if (lck.try_lock()) { // работа с разделяемыми ресурсами: sh+=1; } else { // возможно делаем что-то еще } }
Аналогично, unique_lock поддерживает методы try_lock_for() и try_lock_until(). Использование блокировок по сравнению с ручным использованием мьютекса дает безопасность с точки зрения исключений, и не дает забыть вызвать метод unlock(). В параллельном программировании нам пригодится любая помощь. А что если нам нужны два ресурса, представленные двумя мьютексами? Простой способ заключается в захвате двух мьютексов по очереди: std:: mutex m1; std:: mutex m2; int sh1; // разделяемые данные Int sh2 //... Void f() { //... std:: unique_lock lck1(m1); std:: unique_lock lck2(m2); // работа с разделяемыми ресурсами: sh1+=sh2; }
Этот код может привести к серьезной проблеме, если другой поток попытается захватить m1 и m2 в противоположном порядке, тогда каждый из них будет держать блокировку, необходимую другому потоку для продолжения своей работы, в результате они будут ожидать друг друга вечно (это называется взаимоблокировкой (deadlock)). При большом количестве блокировок в системе это становится реальной опасностью. Именно поэтому стандартные блокировки предоставляют две функции для безопасной попытки захвата двух или более блокировок: Void f() { //... // создаем блокировки, но пока не захватываем мьютексы std:: unique_lock lck1(m1, std:: defer_lock); std:: unique_lock lck2(m2, std:: defer_lock); std:: unique_lock lck3(m3, std:: defer_lock); Lock(lck1, lck2, lck3); // работа с разделяемыми данными }
Очевидно, реализация lock() должна быть тщательно продумана, чтобы избежать взаимоблокировок. По сути, это эквивалентно использованию нескольких вызовов try_lock(). Если во время lock() не удастся захватить ни одной блокировки, то будет сгенерировано исключение. На самом деле, метод lock() может принимать любые аргументы, которые содержат методы lock(), try_lock() и unlock() (как, например, класс mutex), поэтому мы не можем точно говорить о том, какие исключения может генерировать метод lock(); это зависит от его аргументов. Если вы предпочитаете использовать try_lock(), то вам может помочь метод, эквивалентный методу lock(): Void f() { //... // создаем блокировки, но пока не захватываем мьютексы std:: unique_lock lck1(m1, std:: defer_lock); std:: unique_lock lck2(m2, std:: defer_lock); std:: unique_lock lck3(m3, std:: defer_lock); Int x; // добро пожаловать в мир C if ((x = try_lock(lck1, lck2, lck3))==-1) { // работаем с разделяемыми данными } else { // x содержит индекс мьютекса, который не удалось захватить // например, если lck2.try_lock() завершится неудачно, то x==1 } }
См. также:
|