2016-12-06 2 views
0

Как я могу реорганизовать следующий код для использования рекомендуемых lock_guards?Переключение блокировки мьютекса с использованием защитного устройства

bool locked = false; 
bool sync() { 
    if (locked) { 
     mutex.unlock(); 
    } else { 
     mutex.lock(); 
    } 
    locked = !locked; 
    return locked; 
} 

Желаемая модель использования:

while (sync()) { 
    // do safe things 
} 

В основном я пытаюсь подражать with заявление Python. Пример:

from multiprocessing import Lock 
with Lock(): 
    # do safe things 
+0

Не могли бы вы вместо того, чтобы обеспечить пример Python с ' с 'и мьютексом, который вы хотели бы иметь на C++? – michalsrb

+0

Что вы хотите, чтобы значение 'sync()' было? просто переключить замок? –

+0

Плохой дизайн требует плохого кода. Там не должно быть необходимости ** ** для блокировки переключения. – SergeyA

ответ

2

Просто используйте объем:

{ 
    std::lock_guard<std::mutex> lock{mutex}; 

    // Your operations here 
} 

Если вы действительно хотите иметь рамки с заголовком, C++-17 if -с-инициализатор может быть согнута в эту форму легко:

if(std::lock_guard<std::mutex> lock{mutex}; true) { 
    // Your operations here 
} 

... и затем вы можете скрыть его внутри (задумчиво названного) макроса.

Наконец, и с моим снижением от ответственности о том, как использовать эту вещь, вот C++ 14 Реализация: с

template <class T> 
struct Lock { 
    Lock(T &mtx) 
    : guard{mtx} { } 

    constexpr operator bool() const { return false; } 

    std::lock_guard<T> guard; 
}; 

// Replace the pragmas for a compiler other than Clang or GCC 
// so it doesn't complain about the unused variable 
#define withLock(mtx) \ 
    _Pragma("GCC diagnostic push") \ 
    _Pragma("GCC diagnostic ignored \"-Wunused-variable\"") \ 
    if(auto const &_lockGuard = Lock<std::remove_reference_t<decltype(mtx)>>{mtx}); else \ 
    _Pragma("GCC diagnostic pop") 

// ... 

withLock(mutex) { 
    // Your operations here 
} 

... но на самом деле, просто сфера работает отлично и Безразлично» t должен быть документирован и аргументирован для разработчиков кода.

+0

C++ 17 или нет, эта вторая идея должна идти в корзину. У него есть «путающий код», написанный на нем. –

+0

@ RichardHodges приветствую вас определенно не понравится это редактирование тогда :) – Quentin

+0

Мои коллеги будут любить это! –

-1

Вот довольно злой, но работает, хак:

#include <memory> 
#include <mutex> 
#include <iostream> 

#define with(m) for (std::unique_ptr<std::lock_guard<std::mutex>> lock(\ 
        new std::lock_guard<std::mutex>(m)); lock; lock.reset()) 

int main() 
{ 
    std::mutex m; 
    with (m) 
    { 
    std::cout << "got the mutex" << std::endl; 
    } 
} 

with(m) расширяется заголовок for петли, которые

  • создает unique_ptr к lock_guard, который держит mutex
  • в условии цикла, проверяет, что указатель не равен нулю
  • в части приращения сбрасывает указатель.

Точно так же, как и при выполнении блокировки, происходит выполнение цикла, следующего за макросом with(). Немного взломать из-за макроса и указателя, но тем не менее немного чище, чем конструирование цикла while и переключении состояния мьютекса.

Если у вас есть C++ 14, вы можете немного упростить макрос, используя std::make_unique. Если вы можете использовать C++ 17, Quentin's solution будет более элегантным.

Конечно, на самом деле это не C++-способ сделать это, просто взломать какой-то синтаксический сахар. Таким образом, если вы действительно настаиваете на следующий синтаксис Python-как, вы могли бы просто использовать стандартный C++ способ использования lock_guard так:

{ 
    std::lock_guard<std::mutex> lock(my_mutex); 
    // Do whatever 
} 
+0

Почему бы не сделать это незлобой не-взломать? –

+0

Ну, как вам это понравится? Он эмулирует оператор 'with' с поведением типа Python. Но на самом деле это не C++. Отсюда зло и взломать. – mindriot

+0

@RichardHodges Что лучше? – mindriot

5

Просто создайте lockerstd::lock_guard<std::mutex> lock(mutex); и семафор будет автоматически выпущен в конце жизни lock.

std::mutex mutex; 
.... 
{ 
    std::lock_guard<std::mutex> lock(mutex); 
    // do do safe things 
    // mutex will be released here 
} 
0

Ваш дизайн не поддерживается защитными кожухами, и для этого есть веские причины. У вас не должно быть необходимости переключить замок. Правильный шаблон использования для общего ресурса заключается в том, что каждый поток, обращающийся к ресурсу, сначала получает блокировку через охрану, чем использует ресурс, а не существует, что инициирует автоматическую блокировку.

Никто никогда не должен переключаться с замка.

+0

По-моему, в этом случае вы по-прежнему переключаете блокировку, но позволяете правилам C++ об области обрабатывать переключение, а не делать это явно. Явно или неявно, мьютекс все еще переключается. –

0

полный пример того, как я бы нормально подойти к нему:

#include <mutex> 
#include <future> 
#include <iostream> 
#include <vector> 
#include <chrono> 
#include <random> 

// here is the relevant function 

template<class Mutex, class F> 
decltype(auto) with_lock(Mutex& mutex, F&& func) 
{ 
    using mutex_type = std::decay_t<Mutex>; 
    using lock_type = std::lock_guard<mutex_type>; 
    lock_type lock { mutex }; 
    return func(); 
} 

// here is a test 

int main() 
{ 
    std::mutex m; 
    std::default_random_engine eng { std::random_device()() }; 

    std::vector<std::future<void>> futures; 
    for (int i = 0 ; i < 100 ; ++i) 
    { 
     futures.push_back(std::async(std::launch::async, [i, &m, &eng] 
     { 
      std::uniform_int_distribution<int> dist(10, 100); 
      std::this_thread::sleep_for(std::chrono::milliseconds(dist(eng))); 
      with_lock(m, [i] 
      { 
       std::cout << "thread index: " << i << std::endl; 
      }); 
     })); 
    } 

    for (auto& f : futures) 
    { 
     f.get(); 
    } 
} 

выход пробы (примечание, нет гонок на соиЬ):

thread index: 63 
thread index: 62 
thread index: 30 
thread index: 49 
thread index: 25 
thread index: 1 
thread index: 58 
thread index: 33 
thread index: 72 
thread index: 75 
thread index: 11 
thread index: 22 
thread index: 46 
thread index: 41 
thread index: 20 
thread index: 36 
thread index: 37 
thread index: 23 
thread index: 45 
thread index: 82 
thread index: 0 
thread index: 28 
thread index: 88 
thread index: 3 
thread index: 74 
thread index: 84 
thread index: 31 
thread index: 9 
thread index: 34 
thread index: 93 
thread index: 24 
thread index: 98 
thread index: 38 
thread index: 55 
thread index: 43 
thread index: 52 
thread index: 40 
thread index: 69 
thread index: 67 
thread index: 91 
thread index: 89 
thread index: 86 
thread index: 76 
thread index: 21 
thread index: 29 
thread index: 53 
thread index: 81 
thread index: 10 
thread index: 96 
thread index: 68 
thread index: 7 
thread index: 73 
thread index: 78 
thread index: 54 
thread index: 59 
thread index: 83 
thread index: 60 
thread index: 47 
thread index: 19 
thread index: 6 
thread index: 17 
thread index: 56 
thread index: 57 
thread index: 66 
thread index: 70 
thread index: 39 
thread index: 26 
thread index: 13 
thread index: 79 
thread index: 15 
thread index: 5 
thread index: 94 
thread index: 14 
thread index: 77 
thread index: 32 
thread index: 48 
thread index: 87 
thread index: 92 
thread index: 61 
thread index: 80 
thread index: 18 
thread index: 27 
thread index: 12 
thread index: 71 
thread index: 4 
thread index: 2 
thread index: 99 
thread index: 35 
thread index: 50 
thread index: 51 
thread index: 65 
thread index: 64 
thread index: 16 
thread index: 42 
thread index: 90 
thread index: 8 
thread index: 44 
thread index: 85 
thread index: 97 
thread index: 95 
Смежные вопросы