单实例应用程序

一、概念:一个程序在系统中只能启动一个实例,这样的程序称为单实例应用程序。例如Windows下的任务管理器、回收站、播放器、文件系统等等。

 

二、实现思想与方法:

(1)核心思想:在当前系统中,只需要有能表示程序是否启动的标志,那么就可以利用它来实现单实例应用程序。

(2)具体步骤:每当程序启动的时候,都需要先检测这个启动标志,当标志指示已经有实例存在,则当前程序退出,否则把标志置位,再运行业务。

(3)实现单实例应用程序的方法:共享内存、绑定端口、命名管道、文件锁等等。

 

三、实现案例:运用文件锁实现

代码转载:http://www.cnblogs.com/highway-9/p/5517990.html

  1 /************************************************
  2 * 该例程讲解Linux下程序只运行一个实例的编程实现
  3 *
  4 * 编写只运行一个实例的程序有很多种方式,比如通过管道
  5 * 共享内存、文件锁等,主要是要有一个全局flag标志该程序
  6 * 已经在运行了,本程序使用文件锁来实现单实例
  7 ************************************************/
  8 #include <unistd.h>
  9 #include <fcntl.h>
 10 #include <sys/stat.h>   
 11 #include <sys/types.h>
 12 #include <errno.h>
 13 #include <stdio.h>
 14 #include <stdlib.h>
 15 #include <string.h>
 16 #include <string>
 17 
 18 #ifndef PATH_MAX
 19 #define PATH_MAX 1024   // 默认最大路径长度
 20 #endif
 21 
 22 std::string currentExeName()
 23 {
 24     char buf[PATH_MAX] = { '\0' };
 25 
 26     int ret = readlink("/proc/self/exe", buf, PATH_MAX);
 27     if (ret < 0 || ret >= PATH_MAX)
 28     {
 29         return "";
 30     }
 31 
 32     std::string path(buf);
 33     int pos = path.find_last_of("/");
 34     if (pos == -1)
 35     {
 36         return "";
 37     }
 38 
 39     path = path.substr(pos + 1, path.size() - 1);
 40 
 41     return path;
 42 }
 43 
 44 bool runSingleInstance()
 45 {
 46     // 获取当前可执行文件名
 47     std::string processName = currentExeName();
 48     if (processName.empty())
 49     {
 50         exit(1);
 51     }
 52 
 53     // 打开或创建一个文件
 54     std::string filePath = std::string("/var/run/") + processName + ".pid";
 55     int fd = open(filePath.c_str(), O_RDWR | O_CREAT, 0666);
 56     if (fd < 0)
 57     {
 58         printf("Open file failed, error : %s", strerror(errno));
 59         exit(1);
 60     }
 61 
 62     // 将该文件锁定
 63     // 锁定后的文件将不能够再次锁定
 64     struct flock fl;
 65     fl.l_type = F_WRLCK; // 写文件锁定
 66     fl.l_start = 0;
 67     fl.l_whence = SEEK_SET;
 68     fl.l_len = 0;
 69     int ret = fcntl(fd, F_SETLK, &fl);
 70     if (ret < 0)
 71     {
 72         if (errno == EACCES || errno == EAGAIN)
 73         {
 74             printf("%s already locked, error: %s\n", filePath.c_str(), strerror(errno));
 75             close(fd);
 76             return false;
 77         }
 78     }
 79 
 80     // 锁定文件后,将该进程的pid写入文件
 81     char buf[16] = { '\0' };
 82     sprintf(buf, "%d", getpid());
 83     ftruncate(fd, 0);
 84     ret = write(fd, buf, strlen(buf));
 85     if (ret < 0)
 86     {
 87         printf("Write file failed, file: %s, error: %s\n", filePath.c_str(), strerror(errno));
 88         close(fd);
 89         exit(1);
 90     }
 91 
 92     // 函数返回时不需要调用close(fd)
 93     // 不然文件锁将失效
 94     // 程序退出后kernel会自动close
 95     return true;
 96 }
 97 
 98 int main()
 99 {
100     if (!runSingleInstance())
101     {
102         printf("Process is already running\n");
103         return 1;
104     }
105 
106     printf("Process start...\n");
107     sleep(5);
108     printf("Process end...\n");
109 
110     return 0;
111 }

 

posted on 2016-11-18 01:22  yqzheng  阅读(779)  评论(0编辑  收藏  举报

导航