一、简介
Linux下允许本程序只运行一次,以防止对共享数据的破坏。linux各个版本下的检测程序都不相同,但思想相同,可以重复使用。
二、详解
1、Centos下的单程序运行
(1)代码singleton.cpp:
#include <unistd.h>
#include <iostream>
#include <fcntl.h>
#include <string>
#include <string.h>
#include <libgen.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
bool is_prog_run()
{
long pid;
char full_name[1024] = {0};
char proc_name[1024] = {0};
int fd;
pid = getpid();
cout<<"pid:"<<pid<<endl;
sprintf(full_name, "/proc/%ld/cmdline", pid);
if (access(full_name, F_OK) == 0) {
fd = open(full_name, O_RDONLY);
if (fd == -1)
return false;
//lseek(fd, 184, SEEK_SET);
read(fd, proc_name, 1024);
close(fd);
}
else {
return false;
}
//cout<<"proc_name:"<<proc_name<<endl;
char self_proc_name[512] = {0};
char *p = proc_name;
int pt = 0;
while(*p != ' ' && *p != '\0') {
self_proc_name[pt] = *p;
p++;
pt++;
}
//cout<<"self_proc_name:"<<self_proc_name<<endl;
string self_final_name = basename(self_proc_name);
cout<<"self_final_name:"<<self_final_name<<endl;
DIR *dir;
struct dirent *result;
dir = opendir("/proc");
while((result = readdir(dir)) != NULL)
{
if (!strcmp(result->d_name, ".") || !strcmp(result->d_name, "..") || !strcmp(result->d_name, "self") || atol(result->d_name) == pid)
continue;
memset(full_name, 0, sizeof(full_name));
memset(proc_name, 0 ,sizeof(proc_name));
sprintf(full_name, "/proc/%s/cmdline", result->d_name);
if (access(full_name, F_OK) == 0) {
fd = open(full_name,O_RDONLY);
if (fd == -1)
continue;
//lseek(fd, 184, SEEK_SET);
read(fd, proc_name, 1024);
close(fd);
char *q = proc_name;
pt = 0;
memset(self_proc_name, 0, sizeof(self_proc_name));
while(*q != ' ' && *q != '\0') {
self_proc_name[pt] = *q;
q++;
pt++;
}
string other_final_name = basename(self_proc_name);
if (self_final_name == other_final_name) {
cout<<"other_final_name:"<<other_final_name<<endl;
return true;
}
}
}
return false;
}
int main(int argc, char *argv[])
{
int ch;
if (is_prog_run()) {
cout<<"ERROR:one aplication is running"<<endl;
exit(1);
}
while(1){cout<<"go.........."<<endl;sleep(1);}
return 0;
}
(2)编译运行
g++ -o singleton singleton.cpp
./singleton
一个终端先执行:
另一个终端再执行(提示错误,只能运行一个程序):
2、AIX、HP、TRUE64下单程序运行
(1)代码singleton.cpp:
/*
*检测是否有相同的程序同时运行,包括AIX、HP、TRUE64
*/
#include <iostream>
#include <string>
#include <vector>
#include <dirent.h>
#include <unistd.h>
#include <libgen.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define AIX
typedef bool(*CALL_BACK)(string, string);
void string_to_array(const string& the_str, char delimiter, vector<string>& the_vector)
{
string dst = "";
int i;
the_vector.resize(0);
for (i = 0; i < the_str.length(); i++) {
if (the_str[i] != delimiter) {
if (the_str[i] == ' ') continue;
dst += the_str[i];
}
else {
if (!dst.empty()) {
the_vector.push_back(dst);
dst = "";
}
}
}
if (!dst.empty()) the_vector.push_back(dst);
}
bool is_prog_run_once(CALL_BACK call_back)
{
#if defined(AIX)
DIR* dirp;
dirent ent;
dirent* result;
char full_name[1024];
int fd;
long pid;
char proc_name[1024];
pid = getpid();
sprintf(full_name, "/proc/%ld/psinfo", pid);
if (access(full_name, F_OK) == 0) {
fd = open(full_name, O_RDONLY);
if (fd == -1)
return false;
lseek(fd, 184, SEEK_SET);
read(fd, proc_name, 1024);
close(fd);
} else {
return false;
}
#ifdef DEBUGRUN
cout<<"full_name:"<<full_name<<endl;
cout<<"proc_name:"<<proc_name<<endl;
#endif
vector<string> tmp_array;
int ch;
string_to_array(proc_name, ' ', tmp_array);
char* self_argv[256];
//assert(tmp_array.size() <= 256);
for (int i = 0; i < tmp_array.size(); i++)
self_argv[i] = const_cast<char*>(tmp_array[i].c_str());
char sz_self_proc_name[512] ;
strcpy(sz_self_proc_name, tmp_array[0].c_str()) ;
string self_proc_name = basename(sz_self_proc_name);
string self_host_id;
string self_module_id;
string self_proc_id;
optind = 1;
while ((ch = getopt(tmp_array.size(), self_argv, ":p:m:")) != -1) {
switch (ch) {
case 'm':
self_module_id = optarg;
break;
case 'p':
self_proc_id = optarg;
break;
}
}
dirp = opendir("/proc");
if (!dirp)
return false;
#ifdef DEBUGRUN
cout<<"sz_self_proc_name:"<<sz_self_proc_name<<endl;
cout<<"self_module_id:"<<self_module_id<<endl;
cout<<"self_proc_id:"<<self_proc_id<<endl;
#endif
while (readdir_r(dirp, &ent, &result) == 0 && result != 0) {
if (!strcmp(ent.d_name, ".") || !strcmp(ent.d_name, "..") || atol(ent.d_name) == pid)
continue;
sprintf(full_name, "/proc/%s/psinfo", ent.d_name);
if (access(full_name, F_OK) == 0) {
fd = open(full_name,O_RDONLY);
if (fd == -1)
continue;
lseek(fd, 184, SEEK_SET);
read(fd, proc_name, 1024);
close(fd);
string_to_array(proc_name, ' ', tmp_array);
char* other_argv[256];
//assert(tmp_array.size() <= 256);
for (int i = 0; i < tmp_array.size(); i++)
other_argv[i] = const_cast<char*>(tmp_array[i].c_str());
char sz_other_proc_name[512] ;
strcpy(sz_other_proc_name, tmp_array[0].c_str()) ;
string other_proc_name = basename(sz_other_proc_name);
string other_module_id;
string other_proc_id;
optind = 1;
while ((ch = getopt(tmp_array.size(), other_argv, ":m:p:")) != -1) {
switch (ch) {
case 'm':
other_module_id = optarg;
break;
case 'p':
other_proc_id = optarg;
break;
}
}
#ifdef DEBUGRUN
cout << "self_proc_name = [" << self_proc_name << "]" << std::endl ;
cout << "other_proc_name = [" << other_proc_name << "]" << std::endl ;
#endif
if (/*self_proc_name != other_proc_name ||*/self_proc_id != other_proc_id)
continue;
if (self_module_id==other_module_id){
closedir(dirp);
return true;
}
if(call_back!=NULL&&(*call_back)(self_module_id,other_module_id)){//返回true,则表式存在冲突的模块已经在运行
closedir(dirp);
return true;
}
}
}
closedir(dirp);
return false;
#endif
#ifdef HPUX
pst_status proc_status ;
vector<string> self_argvs ;
vector<string> proc_argvs ;
pid_t self_pid = getpid();
if (pstat_getproc(&proc_status, sizeof(struct pst_status), 0, self_pid) == 1) {
string_to_array(proc_status.pst_cmd, ' ', self_argvs) ;
if (self_argvs.size() < 7) {
return false ;
}
} else {
return false ;
}
proc_status.pst_idx = 0;
while (1) {
int nret ;
nret = pstat_getproc(&proc_status, sizeof(struct pst_status), 1, proc_status.pst_idx) ;
proc_status.pst_idx ++ ;
if (nret == 1) {
proc_argvs.clear() ;
string_to_array(proc_status.pst_cmd, ' ', proc_argvs) ;
if (proc_argvs.size() >= 7) {
int i ;
for ( i = 0; i < 7; i ++) {
if (self_argvs[i] != proc_argvs[i])
break;
}
if (i >= 7 && proc_status.pst_pid != self_pid) {
return true ;
}
}
} else if (errno == EOVERFLOW) {// if match 64bits process and this program was compiled under 32bits mode this error would occur
continue;
} else
break;
}
return false ;
#endif
#ifdef TRUE64
DIR* dirp;
dirent ent;
dirent* result;
char full_name[1024];
int fd;
long pid;
char proc_name[1024];
struct prpsinfo psinfo ;
char arglist[PSARGS_SZ + 1] ;
int i ;
pid = getpid();
sprintf(full_name, "/proc/%ld", pid);
if (access(full_name, F_OK) == 0) {
fd = open(full_name, O_RDONLY);
if (fd == -1)
return false;
if (ioctl(fd, PIOCPSINFO, &psinfo) < 0) {
close(fd) ;
return false ;
}
close(fd);
} else {
return false;
}
vector<string> tmp_array;
int ch;
memcpy(arglist, psinfo.pr_psargs, PSARGS_SZ) ;
arglist[PSARGS_SZ] = 0 ;
for (i = 0; i < PSARGS_SZ; i ++) {
arglist[i] = (arglist[i] == 0)?' ':arglist[i] ;
}
string_to_array(arglist, ' ', tmp_array);
char* self_argv[256];
//assert(tmp_array.size() <= 256);
for (int i = 0; i < tmp_array.size(); i++)
self_argv[i] = const_cast<char*>(tmp_array[i].c_str());
char sz_self_proc_name[512] ;
strcpy(sz_self_proc_name, tmp_array[0].c_str()) ;
string self_proc_name = basename(sz_self_proc_name);
string self_host_id;
string self_module_id;
string self_proc_id;
vector<string> self_threads;
optind = 1;
while ((ch = getopt(tmp_array.size(), self_argv, ":h:m:p:t:")) != -1) {
switch (ch) {
case 'h':
self_host_id = optarg;
break;
case 'm':
self_module_id = optarg;
break;
case 'p':
self_proc_id = optarg;
break;
case 't':
self_threads.push_back(optarg);
break;
}
}
#ifdef DEBUGLY
cout << "self_proc_name =[" << self_proc_name << "]" << std::endl ;
cout << "self_host_id =[" << self_host_id << "]" << std::endl ;
cout << "self_module_id =[" << self_module_id << "]" << std::endl ;
cout << "self_proc_id =[" << self_proc_id << "]" << std::endl ;
if (self_threads.size() > 0) {
cout << "self_thread_id =[" << self_threads[0] << "]" << std::endl ;
}
#endif
dirp = opendir("/proc");
#ifdef DEBUGLY
cout << "after opendir" << std::endl ;
#endif
if (!dirp)
return false;
#ifdef DEBUGLY
cout << "before readdir_r" << std::endl ;
#endif
while (readdir_r(dirp, &ent, &result) == 0 && result != 0) {
if (!strcmp(ent.d_name, ".") || !strcmp(ent.d_name, "..") || atol(ent.d_name) == pid)
continue;
sprintf(full_name, "/proc/%s", ent.d_name);
#ifdef DEBUGLY
cout << "full_name = [" << full_name << "]" << std::endl ;
#endif
if (access(full_name, F_OK) == 0) {
fd = open(full_name,O_RDONLY);
if (fd == -1)
continue;
if (ioctl(fd, PIOCPSINFO, &psinfo) < 0) {
close(fd) ;
continue ;
}
close(fd);
memcpy(arglist, psinfo.pr_psargs, PSARGS_SZ) ;
arglist[PSARGS_SZ] = 0 ;
for (i = 0; i < PSARGS_SZ; i ++) {
arglist[i] = (arglist[i] == 0)?' ':arglist[i] ;
}
#ifdef DEBUGLY
cout << "before string_to_array other" << std::endl ;
#endif
string_to_array(arglist, ' ', tmp_array);
char* other_argv[256];
//assert(tmp_array.size() <= 256);
for (int i = 0; i < tmp_array.size(); i++)
other_argv[i] = const_cast<char*>(tmp_array[i].c_str());
char sz_other_proc_name[512] ;
strcpy(sz_other_proc_name, tmp_array[0].c_str()) ;
string other_proc_name = basename(sz_other_proc_name);
string other_host_id;
string other_module_id;
string other_proc_id;
vector<string> other_threads;
optind = 1;
while ((ch = getopt(tmp_array.size(), other_argv, ":h:m:p:t:")) != -1) {
switch (ch) {
case 'h':
other_host_id = optarg;
break;
case 'm':
other_module_id = optarg;
break;
case 'p':
other_proc_id = optarg;
break;
case 't':
other_threads.push_back(optarg);
break;
}
}
#ifdef DEBUGLY
cout << "other_proc_name =[" << other_proc_name << "]" << std::endl ;
cout << "other_host_id =[" << other_host_id << "]" << std::endl ;
cout << "other_module_id =[" << other_module_id << "]" << std::endl ;
cout << "other_proc_id =[" << other_proc_id << "]" << std::endl ;
cout << "---------------------------------------------" << std::endl << std::endl ;
#endif
if (self_proc_name != other_proc_name || self_host_id != other_host_id
|| self_module_id != other_module_id || self_proc_id != other_proc_id)
continue;
if (self_threads.size() == 0 || other_threads.size() == 0)
return true;
for (vector<string>::const_iterator iter = self_threads.begin(); iter != self_threads.end(); ++iter) {
if (std::find(other_threads.begin(), other_threads.end(), *iter) != other_threads.end())
return true;
}
}
}
closedir(dirp);
return false;
#else
return false;
#endif
}
bool check_relation(string self, string other)
{
cout<<"self:"<<self<<endl;
cout<<"other:"<<other<<endl;
return false;
}
/*************测试代码***********/
int main()
{
CALL_BACK call_back = check_relation;
bool flag = is_prog_run_once(call_back);
cout<<"falg:"<<flag<<endl;
while(1) {sleep(1);}
return 0;
}
三、总结
(1)读者可根据自己的操作系统选择相应的处理方式,系统不同可能结果会有出入。
(2)上述代码都是检测运行程序的程序名称,若系统中有重复的程序名称则不再使用,可以参考其他的更多的单程序运行方式。
(3)若有建议,请留言,在此先感谢!