操作系统: IBM AIX 5.3
编译器: xlc
Hello Everyone
我有一个项目使用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;
}
感谢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;
}
答案 0 :(得分:0)
尝试使用getprocs()
。我发现它比使用/ proc或ps
进行炮轰更有效。
我在这里举了一个例子:Need help in getting the process name based on the pid in aix