LoginSignup
3
4

More than 5 years have passed since last update.

cv::AutoLock, cv::Mutex

Last updated at Posted at 2015-12-05

この記事はOpenCV Advent Calendar 2015の6日目の記事です.

はじめに

OpenCVでは排他制御に用いる以下の機能を提供しています.

  • cv::AutoLock
  • cv::Mutex

また,これらの機能はマルチプラットフォーム対応であるため,排他制御のコードを
プラットフォーム間で共通化できるというメリットもあります.

この記事ではこれらの機能と使い方を紹介します.

cv::AutoLockクラス

cv::AutoLockクラスは,インスタンスが生存する間においてcv::Mutexクラスの
インスタンスを用いて排他制御を行う仕組みです.以下に疑似コードを紹介します.

{
    cv::AutoLock lock(mutex); // mutexを使ってロックする
    counter++;

    // lockインスタンスが破棄される(=このスコープを出る)とアンロックする
}

AutoLockという名前の由来は,

  • cv::AutoLockクラスのインスタンスを生成した時点でロックを行う
  • cv::AutoLockクラスのインスタンスを破棄した時点でアンロックを行う

ことを内部的に自動で行うことから来ています.

使い方や機能は,C++やBoostで言うところのstd::lock_guard(C++)
boost::mutex::scoped_lock(Boost)と似ているかもしれません.

cv::AutoLockクラスの内部処理

公式ドキュメントを読んで調べようと思ったのですがほとんど情報がありませんでした。。。orz

ということで,気を取り直してmodules/core/include/opencv2/core/utility.hpp
cv::AutoLock実装を読んでみます.

class CV_EXPORTS AutoLock
{
public:
    AutoLock(Mutex& m) : mutex(&m) { mutex->lock(); }
    ~AutoLock() { mutex->unlock(); }
protected:
    Mutex* mutex;
private:
    AutoLock(const AutoLock&);
    AutoLock& operator = (const AutoLock&);
};

上記のコードからもわかるようにcv::AutoLockクラスは,

  • クラスメンバとしてcv::Mutexのインスタンスを持っており,
  • コンストラクタでcv::Mutexのlockメソッドをコールし,
  • デストラクタでcv::Mutexのunlockメソッドをコールしています.

ここで登場するcv::Mutexについては次で説明します,

cv::Mutexクラス

cv::Mutexは排他制御に用いるロック処理を担うクラスであり,
先の説明でも紹介したようにcv::AutoLock内部でも用いられています.

通常,排他制御に用いるロック処理はOSに依存するのですが,
OpenCVが提供するcv::MutexはOSの違いを吸収しているため,
ユーザが環境依存のコードを書く必要がないようになっています.

以下にcv::Mutexが内部的に使用している機能をOS毎にまとめました.

OS 関数
Windows CriticalSection
Linux/MacOS pthread

詳細な実装を知りたい方はmodules/core/include/opencv2/core/utility.hppを参照ください.

サンプルコード

以下にcv::AutoLockを用いて排他制御を行うサンプルコードを紹介します.

サンプルコード(cv::AutoLock)

autolock_test.cpp
#include <opencv2/core.hpp> // coreモジュールにて定義

#include <thread>
#include <mutex>
#include <vector>
#include <iostream>

#define ENABLE_AUTOLOCK

cv::Mutex g_mutex; // cv::Mutexクラスのインスタンス
int g_counter = 0; // カウンタ

void dummyProcessing(void)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

void incrementCounter(void)
{
    dummyProcessing();

#ifdef ENABLE_AUTOLOCK
    cv::AutoLock lock(g_mutex);
#endif

    g_counter++;
}

int main(int argc, const char* argv[])
{
    // このサンプルではスレッド数は500
    std::vector<std::thread> threads(500);

    // 各スレッドにてカウンタを増やす
    for(auto& thread : threads)
    {
        thread = 
            std::thread(incrementCounter);
    }
    for(auto& thread : threads){ thread.join(); }

    // この時点でカウンタは500になっているはず
    std::cout << g_counter << std::endl;

    return 0;
}

また,ENABLE_AUTOLOCKをundefすると排他制御を行わないようになります.
興味のある方は実際に排他制御有り・無しで実行してみて結果の違いを見てみるとよいかもしれません.

おわりに

OpenCVを使ったプログラミングにおいてマルチプラットフォーム対応の排他制御処理を実装する際に

  • cv::AutoLock
  • cv::Mutex

を使用するという選択肢もあります.

備考

筆者は以下の環境で動作確認しました.

  • OpenCV 3.0.0
  • Windows 8.1 Pro(64bit)
  • Visual Studio 2013 Update5
3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4