5

在 Windows 环境中,我不希望我的程序的两个实例同时运行。

有关的

是否使用互斥锁来防止同一程序的多个实例安全运行?

4

10 回答 10

12

如果是你的程序,那么在 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 ...
}

无需变得疯狂复杂,如果您只需要一个简单的检查...

于 2013-01-05T21:28:04.620 回答
10

我认为您需要在继续之前考虑一下您的情况。不止一次“运行同一个程序”有很多不同的解释。比如你

  1. 每台机器一次
  2. 每个登录会话一次
  3. 每个用户一次

所有这些都有不同但相似的解决方案。

最容易描述的是每台机器。在这种情况下,您要创建一个命名的 Mutex。每次启动时,每个程序都必须获得此互斥锁,如果它们成功,它们会在进程生命周期内运行并持有互斥锁。否则,其他一些程序正在运行,它们会立即退出。

不幸的是,这种方法也有其缺点。如果我想弄乱你的程序,我可以创建一个同名的互斥锁。这将阻止您的程序运行任何实例,因为它们无法分辨谁持有互斥锁,只是有东西持有互斥锁。

于 2009-04-29T03:24:31.260 回答
9

您可以在应用程序的第一个实例启动时创建互斥锁。为了防止第二个实例,您需要做的就是检查是否正在使用互斥锁。

实际上,这里有一个关于为此目的使用互斥锁的问题,请查看 JaredPar 的答案。

注意:如果您希望“一个实例”仅应用于用户会话(而不是所有用户),则可以使用本地互斥锁

于 2009-04-29T03:18:03.447 回答
3

最好的方法是使用互斥锁。请参阅使用互斥对象

于 2009-04-29T03:18:46.470 回答
3

另一种简单的解决方案是创建一个适当唯一的全局命名事件(可能是 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;
    }
}
于 2009-04-29T07:36:33.417 回答
2

这是我使用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)
{
 ...
}

因此您可以轻松限制并行进程的数量。

于 2009-04-29T04:39:05.357 回答
2

当您使用 Qt 时,您可以下载QtSingleApplication组件。

于 2009-04-29T11:47:19.603 回答
1

正如其他人所建议的那样,使用互斥锁。

MS 的CreateMutex () 文档有很多有用的信息,并专门解决了使用互斥锁来防止多个程序实例运行的情况。尤其是:

  • 调用CreateMutex()bInitialOwner = FALSE然后调用等待函数(例如WaitForSingleObject())以确保只有一个实例获取互斥锁。
  • 如果您担心拒绝服务攻击,请考虑使用锁定文件。
于 2009-04-29T03:45:03.630 回答
0

在你的程序启动时,你可以枚举你机器上运行的进程

然后如果你看到你已经在运行,退出

于 2009-04-29T03:52:06.657 回答
-1

您可以检查窗口类是否已注册。看看这个MSDN 条目。

于 2009-04-29T03:15:29.643 回答