在C中,我如何以编程方式找出Linux / Ubuntu上是否已经运行进程以避免它启动两次?我正在寻找类似于pidof的东西。
答案 0 :(得分:29)
您可以浏览pid
中的/proc
条目,并在cmdline
文件中检查您的流程,或在readlink
链接上执行exe
(以下使用第一种方法。)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
pid_t proc_find(const char* name)
{
DIR* dir;
struct dirent* ent;
char* endptr;
char buf[512];
if (!(dir = opendir("/proc"))) {
perror("can't open /proc");
return -1;
}
while((ent = readdir(dir)) != NULL) {
/* if endptr is not a null character, the directory is not
* entirely numeric, so ignore it */
long lpid = strtol(ent->d_name, &endptr, 10);
if (*endptr != '\0') {
continue;
}
/* try to open the cmdline file */
snprintf(buf, sizeof(buf), "/proc/%ld/cmdline", lpid);
FILE* fp = fopen(buf, "r");
if (fp) {
if (fgets(buf, sizeof(buf), fp) != NULL) {
/* check the first token in the file, the program name */
char* first = strtok(buf, " ");
if (!strcmp(first, name)) {
fclose(fp);
closedir(dir);
return (pid_t)lpid;
}
}
fclose(fp);
}
}
closedir(dir);
return -1;
}
int main(int argc, char* argv[])
{
if (argc == 1) {
fprintf("usage: %s name1 name2 ...\n", argv[0]);
return 1;
}
int i;
for(int i = 1; i < argc; ++i) {
pid_t pid = proc_find(argv[i]);
if (pid == -1) {
printf("%s: not found\n", argv[i]);
} else {
printf("%s: %d\n", argv[i], pid);
}
}
return 0;
}
答案 1 :(得分:13)
这与John Ledbetter发布的代码相同。引用/ proc / pid /目录中名为stat的文件比cmdline好,因为前者提供了进程状态和进程名称。 cmdline文件提供了用于启动进程的完整参数。所以在某些情况下失败了。约翰给出的想法是好的。在这里,我发布了John的修改代码。我在Linux中查找c中的代码来检查dhcp是否正在运行。使用此代码,我能够做到这一点。我希望它对像我这样的人有用。
#include <sys/types.h>
#include <dirent.h>
#include<unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
pid_t proc_find(const char* name)
{
DIR* dir;
struct dirent* ent;
char buf[512];
long pid;
char pname[100] = {0,};
char state;
FILE *fp=NULL;
if (!(dir = opendir("/proc"))) {
perror("can't open /proc");
return -1;
}
while((ent = readdir(dir)) != NULL) {
long lpid = atol(ent->d_name);
if(lpid < 0)
continue;
snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid);
fp = fopen(buf, "r");
if (fp) {
if ( (fscanf(fp, "%ld (%[^)]) %c", &pid, pname, &state)) != 3 ){
printf("fscanf failed \n");
fclose(fp);
closedir(dir);
return -1;
}
if (!strcmp(pname, name)) {
fclose(fp);
closedir(dir);
return (pid_t)lpid;
}
fclose(fp);
}
}
closedir(dir);
return -1;
}
int main(int argc, char* argv[])
{
int i;
if (argc == 1) {
printf("usage: %s name1 name2 ...\n", argv[0]);
return 1;
}
for( i = 1; i < argc; ++i) {
pid_t pid = proc_find(argv[i]);
if (pid == -1) {
printf("%s: not found\n", argv[i]);
} else {
printf("%s: %d\n", argv[i], pid);
}
}
return 0;
}
答案 2 :(得分:13)
有一些方法可以避免使用/proc
(并且可能有充分的理由这样做,例如/proc
可能根本没有安装,和/或它可能已被符号链接到欺骗性的东西,或者pid已隐藏在/proc
)中。当然,下面的方法看起来不太好,我希望有适当的API!
无论如何,1997年{1.9}的第1.9节说:
使用kill()
为0表示信号编号。此调用有四种可能的结果:
kill()
返回0
这意味着存在一个具有给定PID的进程,并且 系统允许您向其发送信号。它是 系统依赖于该过程是否可能是一个僵尸。
kill()
返回-1,errno
== ESRCH
对于给定的PID或安全性,不存在任何进程 增强功能导致系统否认其存在。 (上 在某些系统中,这个过程可能是一个僵尸。)
kill()
返回-1,errno
== EPERM
系统不允许您终止指定的进程。 这意味着该过程存在(同样,它可能是一个 僵尸)或严厉的安全增强功能(例如你的 不允许进程向任何人发送信号。
kill()
返回-1,其他值为errno
你遇到了麻烦!
最常用的技术是假设EPERM
成功或失败
意味着该过程存在,任何其他错误暗示它
没有。
答案 3 :(得分:3)
pidof在/proc
filesystem上行走。在C中,您可以通过枚举/proc
来执行类似的操作;为每个X打开/proc/X/cmdline
,其中X是一个或多个十进制数的列表。我不知道您是否有任何可移植性要求,但如果您要依赖/proc
的可用性,请记住这一点。
通过包装程序的启动和维护PID文件,在类UNIX系统上更常解决这个问题。有关此方法的经典示例,请参阅/etc/init.d/*
。您需要注意确保读取PID文件的代码以安全的方式(原子地)执行。如果您的目标操作系统具有更强大的初始化(例如systemd),您可以将此工作外包给该工作。