Windows 環境で、プログラムの 2 つのインスタンスを同時に実行したくありません。
関連している
Windows 環境で、プログラムの 2 つのインスタンスを同時に実行したくありません。
関連している
それがあなたのプログラムである場合、Windowsで可能な限り短いバージョン:
int main(int argc, char** argv)
{
CreateMutexA(0, FALSE, "Local\\$myprogram$"); // try to create a named mutex
if(GetLastError() == ERROR_ALREADY_EXISTS) // did the mutex already exist?
return -1; // quit; mutex is released automatically
// ... program code ...
}
単純なチェックだけが必要な場合は、非常に複雑になる必要はありません...
先に進む前に、シナリオを少し検討する必要があると思います。「同じプログラムを複数回実行する」ことには、さまざまな解釈があります。たとえば、あなたは
これらはすべて、似ていますが、異なる解決策を持っています。
説明するのが最も簡単なのは、マシンごとです。この場合、名前付き Mutex を作成します。プログラムごとに 1 回の起動でこのミューテックスを取得する必要があります。成功した場合、プログラムは実行され、プロセスの存続期間中ミューテックスを保持します。そうしないと、他のプログラムが実行中であり、すぐに終了します。
残念ながら、このアプローチには欠点もあります。あなたのプログラムを台無しにしたい場合は、同じ名前のミューテックスを作成できます。これにより、プログラムはミューテックスを保持している人を特定できず、何かがミューテックスを保持しているだけで、インスタンスを実行できなくなります。
アプリケーションの最初のインスタンスの起動時にミューテックスを作成できます。2 番目のインスタンスを防止するには、mutex が使用されているかどうかを確認するだけです。
実際、この目的でミューテックスを使用することについて質問がありました。JaredPar の回答をご覧ください。
注: 「1 つのインスタンス」を (すべてのユーザーではなく) ユーザーのセッション内でのみ適用する場合は、ローカル ミューテックスを使用できます。
最良の方法は、ミューテックスを使用することです。Mutex オブジェクトの使用を参照してください。
別の簡単な解決策は、適切に一意のグローバル名前付きイベント (おそらく GUID 文字列) を作成し、起動時にその存在を確認することです。存在する場合、アプリのインスタンスは既に開始されています。そうでない場合は、イベントが自動的に作成され、引き続き実行できます。例:
// for brevity, a complete set of error handling has been omitted
m_hEvent = CreateEvent(NULL, TRUE, FALSE, szMyUniqueNamedEvent);
switch (GetLastError)
{
// app is already running
case ERROR_ALREADY_EXISTS:
{
CloseHandle(m_hEvent);
// now exit
break;
}
// this is the first instance of the app
case ERROR_SUCCESS:
{
// global event created and new instance of app is running,
// continue on, don't forget to clean up m_hEvent on exit
break;
}
}
これは、boost.interrprocessを使用してスクリプト化したクラスです。これを使用して、GUI と CLI のバージョンを同期します。
あなたはそれが役に立つかもしれません:
#pragma once
#include <boost/interprocess/windows_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
using boost::interprocess::windows_shared_memory;
using boost::interprocess::mapped_region;
using boost::interprocess::open_or_create;
using boost::interprocess::read_write;
using boost::interprocess::interprocess_exception;
class CProcessMutex
{
public:
CProcessMutex()
: m_region()
, m_status(false)
{
initSharedMemory();
Increment();
}
~CProcessMutex()
{
Decrease();
}
public:
int GetCount()
{
return m_status ? *(static_cast<unsigned char*>(m_region.get_address())) : 0;
}
private:
void initSharedMemory()
{
try
{
//Create a native windows shared memory object.
windows_shared_memory shm (open_or_create, "shared_memory", read_write, 1);
//Map the whole shared memory in this process
m_region.swap(mapped_region(shm, read_write));
m_status = true;
}
catch(interprocess_exception &ex)
{
ex.what();
m_status = false;
}
}
void Increment()
{
if(m_status) (*(static_cast<unsigned char*>(m_region.get_address())))++;
}
void Decrease()
{
if(m_status) (*(static_cast<unsigned char*>(m_region.get_address())))--;
}
private:
mapped_region m_region;
bool m_status;
};
使い方は簡単です:
CProcessMutex pm;
size_t current_process_count = pm.GetCount();
if(current_process_count > 1)
{
...
}
そのため、並列処理の数を簡単に制限できます。
Qt を使用する場合、QtSingleApplicationコンポーネントをダウンロードできます。
他の人が示唆しているように、ミューテックスを使用してください。
MS のCreateMutex () ドキュメントには多くの有用な情報があり、プログラムの複数のインスタンスが実行されるのを防ぐためにミューテックスを使用する場合に具体的に対処しています。特に:
CreateMutex()
てbInitialOwner = FALSE
から、待機関数 (例: WaitForSingleObject()
) を呼び出して、1 つのインスタンスだけがミューテックスを取得するようにします。プログラムの起動時に、マシンで実行されているプロセスを列挙できます
次に、すでに実行されていることがわかったら、終了します
ウィンドウクラスが既に登録されているかどうかを確認できます。このMSDN エントリを見てください。