【发布时间】:2015-03-09 23:43:46
【问题描述】:
操作系统:IBM AIX 5.3
编译器:xlc
大家好
我有一个项目,它使用 C 来处理一些使用多进程的文件。子进程数主要取决于传入文件的数量和当前运行的进程数。我需要一种可靠的方法来计算有多少子进程在后台运行。
通过效率比较,直接读取/proc目录可能比调用popen()执行$ ps -ef | grep blah性能更好。
我编写了一个函数来读取/proc/pid/psinfo 中的psinfo 并比较参数。
伪代码如下:
int count = 0;
dp = opendir("/proc");
while (readdir_r(...))
{
if (dir is not a process)
return -1;
if (dir's owner is not current user)
return -2;
if (failed to open "/proc/[pid]/psinfo")
return -3;
if (failed to read "/proc/[pid]/psinfo")
return -4;
if (process's name matches the given pname)
count += 1;
}
return count;
该函数通常在一次调用时完美运行。但是,当嵌入到 while 循环中时,它会返回 -2 或 -3 甚至错误的计数。
函数随机读取/proc/pid的属性失败。它告诉No such file or directory。
最后也有很小的机会得到错误的计数。似乎有一个带有特定 pid 的额外进程,但在使用 ps 打印当前进程时消失了。
我认为在列出父目录后快速读取子目录时发生了任何变化。
我做错了什么还是有什么方法可以避免这种情况?
获取有关 AIX 中 psinfo 的额外信息 http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.files/doc/aixfiles/proc.htm%23files-proc?lang=en[233]
这里是完整的源代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/procfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int countProcess(char *pname)
{
DIR *dir;
int fd;
int pid;
int uid;
int pcounter = 0;
struct psinfo pinfo;
struct dirent entry;
struct dirent *result;
struct stat fsstat;
char path[256];
char process_path[256];
/* Open the /proc directory */
if ((dir = opendir("/proc")) == NULL)
{
return -1;
}
/* Retrieve the current user id */
uid = getuid();
/* Walk through the /proc dir */
for (readdir_r(dir, &entry, &result); result != NULL; readdir_r(dir, &entry, &result))
{
/* See if this is a process, e.g., the dirname is a number
If not, then start off again
*/
if ((pid = atoi(entry.d_name)) == 0)
{
continue;
}
/* Get the attributes of process dir */
snprintf(process_path, sizeof(process_path), "/proc/%s", entry.d_name);
if (stat(process_path, &fsstat) == -1)
{
closedir(dir);
return -2;
}
/* Verify if the process runs by current user
If not, then start off again
*/
if (fsstat.st_uid != uid)
{
continue;
}
/* Open and read from psinfo file */
snprintf(path, sizeof(path), "/proc/%s/psinfo", entry.d_name);
if ((fd = open(path, O_RDONLY)) < 0)
{
close(fd);
closedir(dir);
return -3;
}
if (read(fd, &pinfo, sizeof(pinfo)) < 0)
{
close(fd);
closedir(dir);
return -4;
}
/* String comparison, if same, increase the counter */
if (!strcmp(pinfo.pr_psargs, pname))
{
pcounter++;
}
close(fd);
}
/* returns counter */
closedir(dir);
return pcounter;
}
2015 年 1 月 13 日更新
感谢 CoreyStup。 procinfo.h中提供的getprocs()函数可以绕过竞争条件
这是解决方案的代码
#include <stdio.h>
#include <unistd.h>
#include <procinfo.h>
#include <sys/types.h>
int countProcess(const char *pname)
{
struct procsinfo pinfo;
pid_t pid = 0;
uid_t uid;
char args[256];
int index;
int pcounter = 0;
memset(args, 0, sizeof(args));
uid = getuid();
/* Get procsinfo from internal API */
while (0 < getprocs(&pinfo, (int)sizeof(struct procsinfo), NULL, 0, &pid, 1))
{
/* Skip the process that doesn't belong to current user */
if (pinfo.pi_uid != uid)
{
continue;
}
/* Get process arguments */
if (getargs(&pinfo, sizeof(struct procsinfo), args, sizeof(args)) != 0)
{
return -1;
}
/* getargs returns the args list seperated by 0, we need to use space to replace 0 */
for (index = 0; index < 256 - 1 && !(args[index] == 0 && args[index + 1] == 0); index++)
{
if (args[index] == 0)
{
args[index] = ' ';
}
}
if (!strncmp(args, pname, strlen(pname)))
{
pcounter++;
}
}
return pcounter;
}
【问题讨论】: