如何在 C 或 C 中创建单实例应用程序

新手上路,请多包涵

为了创建一个单实例应用程序,您有什么建议,以便一次只允许运行一个进程?文件锁,互斥锁还是什么?

原文由 whoi 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 463
2 个回答

一个好办法是:

 #include <sys/file.h>
#include <errno.h>

int pid_file = open("/var/run/whatever.pid", O_CREAT | O_RDWR, 0666);
int rc = flock(pid_file, LOCK_EX | LOCK_NB);
if(rc) {
    if(EWOULDBLOCK == errno)
        ; // another instance is running
}
else {
    // this is the first instance
}

请注意,锁定允许您忽略陈旧的 pid 文件(即您不必删除它们)。当应用程序因任何原因终止时,操作系统会为您释放文件锁定。

Pid 文件不是非常有用,因为它们可能是陈旧的(文件存在但进程不存在)。因此,可以锁定应用程序可执行文件本身,而不是创建和锁定 pid 文件。

更高级的方法是使用预定义的套接字名称创建和绑定 unix 域套接字。您的应用程序的第一个实例绑定成功。同样,当应用程序因任何原因终止时,操作系统会取消绑定套接字。当 bind() 失败时,应用程序的另一个实例可以 connect() 并使用此套接字将其命令行参数传递给第一个实例。

原文由 Maxim Egorushkin 发布,翻译遵循 CC BY-SA 3.0 许可协议

所有学分都归马克·拉卡塔所有。我只是做了一些非常小的修饰而已。

主文件

#include "singleton.hpp"
#include <iostream>
using namespace std;
int main()
{
   SingletonProcess singleton(5555); // pick a port number to use that is specific to this app
   if (!singleton())
   {
     cerr << "process running already. See " << singleton.GetLockFileName() << endl;
     return 1;
   }
   // ... rest of the app
}

单例.hpp

 #include <netinet/in.h>
#include <unistd.h>
#include <cerrno>
#include <string>
#include <cstring>
#include <stdexcept>

using namespace std;
class SingletonProcess
{
public:
    SingletonProcess(uint16_t port0)
            : socket_fd(-1)
              , rc(1)
              , port(port0)
    {
    }

    ~SingletonProcess()
    {
        if (socket_fd != -1)
        {
            close(socket_fd);
        }
    }

    bool operator()()
    {
        if (socket_fd == -1 || rc)
        {
            socket_fd = -1;
            rc = 1;

            if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
            {
                throw std::runtime_error(std::string("Could not create socket: ") +  strerror(errno));
            }
            else
            {
                struct sockaddr_in name;
                name.sin_family = AF_INET;
                name.sin_port = htons (port);
                name.sin_addr.s_addr = htonl (INADDR_ANY);
                rc = bind (socket_fd, (struct sockaddr *) &name, sizeof (name));
            }
        }
        return (socket_fd != -1 && rc == 0);
    }

    std::string GetLockFileName()
    {
        return "port " + std::to_string(port);
    }

private:
    int socket_fd = -1;
    int rc;
    uint16_t port;
};

原文由 FreeToGo 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题