ムーブ代入演算子の使用を検討してください。を使用した次のコードswap()
:
upgradable_lock<named_upgradable_mutex> my_demoted_lock(move(my_exclusive_lock));
m_lock.swap(my_demoted_lock);
次のようになります:
m_lock = upgradable_lock<named_upgradable_mutex>(move(my_exclusive_lock));
この特定のケースでは、ムーブ代入演算子は、デフォルトの構築状態(および)であるswap()
ため、副作用なしに交換可能です。m_lock
m_lock.owns() == false
m_lock.mutex() == 0
アップグレード可能なロックにメンバー変数を再利用した場合の意図しない結果は考えられません。ただし、考慮すべきトピックがいくつかあります。
1つの目標は、「他のプロセスがライターになるのを防ぐこと」です。コンストラクターでロックが取得されるWriter
と、コードは他のプロセスがを作成するのを防ぐだけでなく、他のプロセスがを作成するのを防ぎます。その結果、ブロッキング呼び出しは、アプリケーションコードに影響を与えたり、不便にしたりする可能性があります。次のコードを検討してください。Writer
Reader reader;
Writer writer; // This may block, but the application code cannot react
// to it without dedicating an entire thread to the
// construction of the writer.
妥協する代替策は、このコンストラクターを介してロックを取得しようとし、アプリケーションにさらに制御を提供するメンバー関数を追加することです。これにより、他のプロセスがを作成できるようになりますが、複数のプロセスが次の書き込み権限を持つことができなくなります。Writer
Writer
class Writer
{
public:
bool IsPrivileged(); // Returns true if this the privileged Writer.
bool TryBecomePrivileged(); // Non-blocking attempt to become the
// privileged Writer. Returns true on success.
bool BecomePrivileged(); // Blocks waiting to become the privileged
// Writer. Returns true on success.
void RelinquishPrivileges(); // We're not worthy...we're not worthy...
enum Status { SUCCESS, NOT_PRIVILEGED };
Status Write( const std::string& ); // If this is not the privileged Writer,
// then attempt to become it. If the
// attempt fails, then return
// NOT_PRIVILEGED.
};
メソッド内で、「 do write hereWriter::Write()
」コードの呼び出しのいずれかが例外をスローすると、スタックがアンワインドされ、次のようになります。
my_exclusive_lock
排他ロックを解放し、他のプロセスがアップグレード可能なロックを取得できるようにします。
m_lock
移動中に所有権が譲渡されたときにm_lock.mutex()
設定されているように、ミューテックスへのハンドルがありません。null
my_exclusive_lock
- をさらに呼び出すと、排他ロックを取得せず
Writer::Write()
に書き込みを試みます。ミューテックスへのハンドルがあったとしても、になりますので、への転送はロックを試みません。m_lock
m_lock.owns()
false
my_exclusive_lock
プログラムの例を次に示します。
#include <boost/interprocess/sync/named_upgradable_mutex.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/upgradable_lock.hpp>
#include <boost/move/move.hpp>
#include <iostream>
int main()
{
namespace bip = boost::interprocess;
typedef bip::named_upgradable_mutex mutex_t;
struct mutex_remove
{
mutex_remove() { mutex_t::remove( "example" ); }
~mutex_remove() { mutex_t::remove( "example" ); }
} remover;
// Open or create named mutex.
mutex_t mutex( bip::open_or_create, "example" );
// Acquire upgradable lock.
bip::upgradable_lock< mutex_t > m_lock( mutex, bip::try_to_lock );
std::cout << "upgradable lock own: " << m_lock.owns()
<< " -- mutex: " << m_lock.mutex()
<< std::endl;
// Acquire the exclusive lock.
{
std::cout << "++ Entering scope ++" << std::endl;
std::cout << "Transferring ownership via move: Upgradable->Scoped"
<< std::endl;
bip::scoped_lock< mutex_t > exclusive_lock( boost::move( m_lock ) );
std::cout << "upgradable lock owns: " << m_lock.owns()
<< " -- mutex: " << m_lock.mutex()
<< "\nexclusive lock owns: " << exclusive_lock.owns()
<< " -- mutex: " << exclusive_lock.mutex()
<< std::endl;
// do write here...
// Demote lock from exclusive to just an upgradable.
std::cout << "Transferring ownership via move: Scoped->Upgradable"
<< std::endl;
m_lock = bip::upgradable_lock< mutex_t >( boost::move( exclusive_lock ) );
std::cout << "upgradable lock owns: " << m_lock.owns()
<< " -- mutex: " << m_lock.mutex()
<< "\nexclusive lock owns: " << exclusive_lock.owns()
<< " -- mutex: " << exclusive_lock.mutex()
<< std::endl;
std::cout << "-- Exiting scope --" << std::endl;
}
std::cout << "upgradable lock own: " << m_lock.owns()
<< " -- mutex: " << m_lock.mutex()
<< std::endl;
return 0;
}
これにより、次の出力が生成されます。
アップグレード可能なロック独自:1-ミューテックス:0xbff9b21c
++スコープに入る++
移動による所有権の譲渡:アップグレード可能->スコープ
アップグレード可能なロック所有:0 --mutex:0
排他ロック所有:1-ミューテックス:0xbff9b21c
移動による所有権の譲渡:スコープ->アップグレード可能
アップグレード可能なロックの所有者:1-ミューテックス:0xbff9b21c
排他ロック所有:0 --mutex:0
-スコープを終了します-
アップグレード可能なロック独自:1-ミューテックス:0xbff9b21c