浅谈Linux Process status,环境锁
这两天在处理一个相应问题,一个系统希望实行命令互斥,举个例子就是如果我打开了两个命令窗口,分别在这两个窗口中运行两种操作,这些操作是互斥的,即命令2要等待命令1执行完成后再执行。
这看似可以用简单的锁机制来实现,但实际处理时还要判断1号窗口的进程状态,用户2不会无线等待用户1的命令执行,会去系统中查看用户1的命令执行情况,如果是正在执行则继续等待,如果这个进程被暂停或者有其他情况,则用户2可以从反馈中知道具体信息
1 sub lock_environment { 2 my ($self) = @_; 3 4 return SUCCESS if $self->get_parent(); 5 my $process_info = $self->get_process_info(); 6 7 while ($self->_validate_environment_lock() == ERR_ENV_LOCKED) { 8 printf( 9 "%s is running cvc, PID: %s, will retry in 10 seconds, please wait...........\n", 10 $process_info->{user_id}, 11 $process_info->{process_id} 12 ); 13 sleep(10); 14 } 15 16 my @ret = $self->_update_env_lock_info( 17 $$, 18 $self->get_login_id(), 19 $self->get_current_environment(), 20 strftime("%Y-%m-%d %H:%M:%S", localtime())); 21 return @ret unless $ret[0] == SUCCESS; 22 23 return SUCCESS; 24 }
1 sub _validate_environment_lock { 2 my ($self) = @_; 3 4 my $process_info = $self->get_process_info(); 5 6 return SUCCESS if (!$process_info); 7 8 my @rets = $self->_get_process_status($process_info->{process_id}); 9 10 my $process_detail = $rets[1]; 11 my @post_process_detail; 12 foreach my $str (@$process_detail) { 13 $str =~ s/\s//g; 14 push @post_process_detail, $str; 15 } 16 my @present_pid = grep {($process_info->{process_id}.$process_info->{user_id}) eq $_ } @$process_detail; 17 18 return ERR_ENV_LOCKED if ( 19 ((scalar(@present_pid)) >0) && 20 $process_info->{env} eq $self->get_current_environment() 21 ); 22 23 $self->unlock_environment(); 24 25 return SUCCESS; 26 27 }
1 sub _get_process_status { 2 my ($self, $process_id) = @_; 3 4 my @rets; 5 return (ERR_PROCESS_ID) unless $process_id ; 6 7 $self->_run_cmd_as( 8 sprintf( 9 "ps -p %s -o pid -o user", 10 $process_id 11 ), 12 sub { 13 my ($line) = @_; 14 push @rets, $line; 15 16 $self->_log($line); 17 } 18 ); 19 return (SUCCESS, \@rets); 20 }
1 sub _run_cmd_as { 2 my ($self, $cmd, $callback, $dir) = @_; 3 4 my $cmd2 = $cmd; 5 my $run_as_user = $self->get_run_as_user(); 6 my $work_dir = $dir || $self->get_public_env_dir(); 7 8 # The -H switch instructs sudo to set $HOME to target users 9 # which is expected by git 10 my @parts = split(/&&/, $cmd); 11 foreach my $p (@parts) { 12 next if $p =~ /sudo -u/; 13 $p = sprintf( 14 "sudo -u %s -H qcvc_operator %s %s", 15 $run_as_user, 16 DEFAULT_WRAPPER_PASSWORD, 17 $p 18 ); 19 } 20 $cmd2 = sprintf("cd '%s' && %s ", $work_dir, join('&&', @parts)); 21 return $self->_run_cmd($cmd2, $callback); 22 }
具体实现上用到了一些ps的知识
ps aux
a = show processes for all users
u = display the process's user/owner
x = also show processes not attached to a terminal
ps -p xxx 检索pid
ps -p xxx -o stat 检索pid, report形式只有pid和stat, -o可以多参数,例如ps -p xxx -o stat -o user
ps aux |grep xxx | grep xxx 针对某些关键词检索pid
pid是可重用分配的,如果一个pid被kill,在下一某个时刻会它可能会被分配给其他的进程
STAT狀態位常見的狀態字符
D 无法中断的休眠状态(通常 IO 的进程);
R 正在运行可中在队列中可过行的;
S 处于休眠状态;
T 停止或被追踪;
W 进入内存交换 (从内核2.6开始无效);
X 死掉的进程 (基本很少見);
Z 僵尸进程;
< 优先级高的进程
N 优先级较低的进程
L 有些页被锁进内存;
s 进程的领导者(在它之下有子进程);
l 多进程的(使用 CLONE_THREAD, 类似 NPTL pthreads);
+ 位于后台的进程组;