zoukankan      html  css  js  c++  java
  • 实现单实例的应用程序

    今天面试,做了两道面试题,有道题,也是非常的有趣,下面简单的说说,原题是:"有哪些方法可以实现单实例的应用程序?选择一种方法阐述它到底实现原理,流程及优缺点?

      然后他们给的答案是:信号量,共享内存,命名管道,绑定端口等。

      我顿时感觉整个人都不好了,首先想到的是微软操作系统的单实例的应用程序,再转到c++方面,也只有单例模型了。在我的脑海里没有关于linux这些单实例的知识。从网上找了找,看了看,说的也是有道理,是在下知识狭隘了。

    转自http://www.cnblogs.com/highway-9/p/5517990.html

    Linux编程之《只运行一个实例》
    有些时候,我们要求一个程序在系统中只能启动一个实例。比如,Windows自带的播放软件Windows Medea Player在Windows里就只能启动一个实例。原因很简单,如果同时启动几个实例,却播放不同的文件,那么声音和图像就会引起混乱。在设计模式中,就有一个SINGLETON模式。对于程序而言,我们只有在程序启动的时候去检测某个设置,如果程序没有启动,就把设置更新为程序已经启动,然后正常启动程序;如果程序已经启动,那么就终止程序的启动。在程序退出的时候把设置恢复为程序没有启动。按照上面的思路,我们很容易就能想出一些方法:

    文件锁
    共享内存
    管道
    注册表(windows实现)
    etc...
    该实例是使用文件锁来实现单例的,下面将完整代码贴上。


    /************************************************
    * 该例程讲解Linux下程序只运行一个实例的编程实现
    *
    * 编写只运行一个实例的程序有很多种方式,比如通过管道
    * 共享内存、文件锁等,主要是要有一个全局flag标志该程序
    * 已经在运行了,本程序使用文件锁来实现单实例
    ************************************************/
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <string>

    #ifndef PATH_MAX
    #define PATH_MAX 1024 // 默认最大路径长度
    #endif

    std::string currentExeName()
    {
    char buf[PATH_MAX] = {''};

    int ret = readlink("/proc/self/exe", buf, PATH_MAX);
    if (ret < 0 || ret >= PATH_MAX)
    {
    return "";
    }

    std::string path(buf);
    int pos = path.find_last_of("/");
    if (pos == -1)
    {
    return "";
    }

    path = path.substr(pos + 1, path.size() - 1);

    return path;
    }

    bool runSingleInstance()
    {
    // 获取当前可执行文件名
    std::string processName = currentExeName();
    if (processName.empty())
    {
    exit(1);
    }

    // 打开或创建一个文件
    std::string filePath = std::string("/var/run/") + processName + ".pid";
    int fd = open(filePath.c_str(), O_RDWR | O_CREAT, 0666);
    if (fd < 0)
    {
    printf("Open file failed, error : %s", strerror(errno));
    exit(1);
    }

    // 将该文件锁定
    // 锁定后的文件将不能够再次锁定
    struct flock fl;
    fl.l_type = F_WRLCK; // 写文件锁定
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    int ret = fcntl(fd, F_SETLK, &fl);
    if (ret < 0)
    {
    if (errno == EACCES || errno == EAGAIN)
    {
    printf("%s already locked, error: %s ", filePath.c_str(), strerror(errno));
    close(fd);
    return false;
    }
    }

    // 锁定文件后,将该进程的pid写入文件
    char buf[16] = {''};
    sprintf(buf, "%d", getpid());
    ftruncate(fd, 0);
    ret = write(fd, buf, strlen(buf));
    if (ret < 0)
    {
    printf("Write file failed, file: %s, error: %s ", filePath.c_str(), strerror(errno));
    close(fd);
    exit(1);
    }

    // 函数返回时不需要调用close(fd)
    // 不然文件锁将失效
    // 程序退出后kernel会自动close
    return true;
    }

    int main()
    {
    if (!runSingleInstance())
    {
    printf("Process is already running ");
    return 1;
    }

    printf("Process start... ");
    sleep(5);
    printf("Process end... ");

    return 0;
    }

    转自 http://www.linuxdiyf.com/linux/18341.html
    Linux下程序单例模式的保证机制:/var/run/*.pid
    在Linux 系统中/var/run下有很多以pid结尾的文件,这个其实是为了保证程序以单例模式运行而设计的。程序在启动后,首先打开(如果没有则创建)/var/run/xx.pid,然后尝试去设置文件锁,如果成功,则将程序的里程ID写入该文件,写入后注意不要关闭文件或解锁;如果加锁失败,表明程序已经有一个进程在运行了,则退出此次启动。此机制在一些程序尤其是服务器程序中很常见,例如sip服务器kamailio中就是这样保证程序以单例模式运行的。

    注:程序退出后,文件锁自动解锁。

    #include <stdio.h> 
    #include <string.h> 
    #include <fcntl.h> 
    #include <stdlib.h> 
    #define DEFAULT_FILE "/var/run/test.pid" 

    int main(int argc, char *argv[]) 

    int fd = -1; 
    char buf[32]; 
    fd = open(DEFAULT_FILE, O_WRONLY | O_CREAT, 0666); 
    if (fd < 0) { 
    perror("Fail to open"); 
    exit(1); 

    struct flock lock; 
    bzero(&lock, sizeof(lock)); 
    if (fcntl(fd, F_GETLK, &lock) < 0) { 
    perror("Fail to fcntl F_GETLK"); 
    exit(1); 

    lock.l_type = F_WRLCK; 
    lock.l_whence = SEEK_SET; 
    if (fcntl(fd, F_SETLK, &lock) < 0) { 
    perror("Fail to fcntl F_SETLK"); 
    exit(1); 

    pid_t pid = getpid(); 
    int len = snprintf(buf, 32, "%d ", (int)pid); 
    write(fd, buf, len); //Write pid to the file 

    printf("Hello world "); 

    while(1); 
    return 0; 
    }
    编译:
    gcc -o test test.c

    运行:

    1.打开终端: ./test

    cat /var/run/test.pid
    23409
    2.打开另一终端:./test,打印错误如下:

    Fail to fcntl F_SETLK: Resource temporarily unavailable

    表示程序已经有实例运行。

    from:https://blog.csdn.net/wrzfeijianshen/article/details/53206382

  • 相关阅读:
    POJ 3258 (NOIP2015 D2T1跳石头)
    POJ 3122 二分
    POJ 3104 二分
    POJ 1995 快速幂
    409. Longest Palindrome
    389. Find the Difference
    381. Insert Delete GetRandom O(1)
    380. Insert Delete GetRandom O(1)
    355. Design Twitter
    347. Top K Frequent Elements (sort map)
  • 原文地址:https://www.cnblogs.com/lidabo/p/10250809.html
Copyright © 2011-2022 走看看