Управление процессами и нитями. Ознакомление со средствами управления многопоточным функционированием в операционной системе QNX

Страницы работы

Фрагмент текста работы

Продемонстрируем действие функций этого семейства на примере программы father.c:

Программа father.c:

#include <process.h>

#include <stdio.h>

#include <stdlib.h>

char * const args[]={

       "./son.out",

       NULL};

main(int argc, char *argv[]){

       int status;

       switch(argv[1][0]){

       case '1':

               spawnl(P_WAIT,"./son.out","son", NULL);

               printf("father still live!\n");

               break;

       case '2':

               spawnle(P_NOWAIT,"./son.out","son",NULL,NULL);

               printf("father still live!\n");

               break;

       case '3':

               spawnlp(P_NOWAITO,"./son.out","son",NULL);

               printf("father still live!\n");

               break;

       case '4':

               spawnv(P_OVERLAY,"./son.out",args);

               printf("father still live!\n");

               break;

       case '5':

               spawnvp(P_WAIT,"./son.out",args);

               printf("father still live!\n");

               break;

       }

       wait(&status);

       printf("father is dying\n");

}

Программа son.c:

#include <stdio.h>

main(){

       sleep(5);

       printf("I'm son\n");

}

Результат работы:

$ cc -o father.out father.c

$ cc -o son.out son.c

$ ./father.out 1

I'm son

father still live!

father is dying

$ ./father.out 2

father still live!

I'm son

father is dying

$ ./father.out 3

father still live!

father is dying

$ I'm son

$ ./father.out 4

I'm son

$ ./father.out 5

I'm son

father still live!

father is dying

Если провести аналогии с POSIX-функциями, то spawn-семейство заменяет конструкцию fork() + exec[l,e,v,p](), расширенную дополнительными режимами. Так мы наблюдаем приостановку выполнения father на время работы son в режиме P_WAIT, что соответствует введению в программу функции wait(). Режимы P_NOWAIT и P_NOWAITO аналогичны паре fork() + exec(), различие между ними покажем дальше. P_OVERLAY – просто exec().

Для иллюстрации методов решения проблемы zombie используем набор программ. Во-первых, father2.c и son2.c, чтобы продемонстрировать факт появления zombie.

Программа father2.c:

#include <process.h>

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

main(int argc, char *argv[]){

       int status;

       //signal(SIGCHLD,SIG_IGN);

       spawnl(P_NOWAIT,argv[1],argv[1],NULL);

       printf("father still live!\n");

       while(1){

               sleep(1);

       }

}

Программа son2c:

#include <stdio.h>

#include <process.h>

main(){

       sleep(5);

       printf("I'm son, my PID is %i\n",getpid());

}

Первый способ: игнорировать сигнал SIGCHLD, посылаемый потомком:

Программа father3.c:

#include <process.h>

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

main(int argc, char *argv[]){

       int status;

       signal(SIGCHLD,SIG_IGN);

       spawnl(P_NOWAIT,argv[1],argv[1],NULL);

       printf("father still live!\n");

       while(1){

               sleep(1);

       }

}

Программа son3.c:

#include <stdio.h>

#include <process.h>

#include <signal.h>

main(){

       sleep(5);

       printf("I'm son, my PID is %i\n",getpid());

}

Второй способ: использование при обращении к spawn() режима P_NOWAITO, который подразумевает наличие признака _SPAWN_NOZOMBIE:

Программа father4.c:

#include <process.h>

#include <stdio.h>

#include <stdlib.h>

main(int argc, char *argv[]){

       int status;

       spawnl(P_NOWAITO,argv[1],argv[1],NULL);

       printf("father still live!\n");

       while(1){

               sleep(1);

       }

}

В результате можно наблюдать следующее:

$ cc -o father2.out father2.c

$ cc -o son2.out son2.c

$ ./father2.out

$ ./father2.out 2

father still live!

I'm son, my PID is 1114152

$ pidin -p 1114152

     pid tid name               prio STATE       Blocked

 1114152     (Zombie)

$ cc -o son3.out son3.c

$ cc -o father3.out father3.c

$ ./father3.out ./son3.out

father still live!

I'm son, my PID is 1253416

$ pidin -p 1253416

     pid tid name               prio STATE       Blocked

pidin: couldn't open /proc/1253416/as: No such file or directory

$ cc -o son3.out son3.c

$ cc -o father4.out father4.c

$ ./father4.out ./son3.out

father still live!

I'm son, my PID is 1298472

$ pidin -p 1298472

     pid tid name               prio STATE       Blocked

pidin: couldn't open /proc/1298472/as: No such file or directory

7. Управление приоритетами

Помимо описанного выше способа управления приоритетами при помощи утилиты nice, эту проблему можно решить с помощью функций библиотеки sched.

int getpriority(pid_t pid)

int setpriority(pid_t pid, int prio)

где      pid – PID процесса, операцию над которым требуется совершить

            prio – новое значение его приоритета

Рассмотрим использование этих функций на примере программы getp.c, которая позволяет получить сведения о текущем значении приоритета процесса (в нашем случае – программма test_proc.c) по PID и изменить его.

Программа getp.c:

#include <stdio.h>

#include <sched.h>

#include <stdio.h>

main(int argc, char* argv[]){

       int j, i=0, pid=0;

       if(argc<2)

               exit(-1);

       while(argv[1][i]){

               i++;

       }

       for(j=0;j<i;j++){

               pid=pid*10+argv[1][j]-0x30;

       }

       j=getprio(pid);      

       printf("Priority of PID %i is equal to %i\nEnter increment: ",pid,j);

       scanf("%i",&i);

       setprio(pid,j+i);

       printf("Now priority of PID %i is equal to %i\n",pid,j=getprio(pid));

}

Программа test_proc.c:

#include <stdio.h>

#include <process.h>

main(){

       printf("test_proc PID is %i\n",getpid());

       while(1){

               sleep(1);

       }

}

Результат работы:

$ ./test_proc.out&

$ cc -o getp.out getp.c

$ ./getp.out 1548325

Priority of PID 1548325 is equal to 10

Enter increment: 5

Now priority of PID 1548325 is equal to 15

$ ps -l -p 1548325

       F S   UID        PID       PPID  C PRI  NI ADDR    SZ WCHAN TTY          TIME CMD

00000200 -   100    1548325    1355809  -  15   0    -  568K -     ?        00:00:00 ./test_proc.out

Также возможно использовать семейство функций, предназначенных для работы с параметрами процесса, относящимися к задаче планирования, оформленными в структуру sched_param: sched_getparam() и sched_setparam().

Программа getp2.c:

#include <stdio.h>

#include <sched.h>

#include <stdio.h>

main(int argc, char* argv[]){

       struct sched_param str;

       int j, i=0, pid=0;

       if(argc<2)

               exit(-1);

       while(argv[1][i]){

               i++;

       }

       for(j=0;j<i;j++){

               pid=pid*10+argv[1][j]-0x30;

       }

       sched_getparam(pid, &str);   

       printf("Priority of PID %i is equal to %i\nEnter increment: ",pid,str.sched_priority);

       scanf("%i",&i);

       str.sched_priority+=i;

       sched_setparam(pid,&str);

       sched_getparam(pid,&str);

       printf("Now priority of PID %i is equal to %i\n",pid,str.sched_priority);

}

Результат работы:

$ cc -o getp2.out getp2.c

$ ./getp2.out 1810469

Priority of PID 1810469 is equal to 15

Enter increment: 1

Now priority of PID 1810469 is equal to 16

$ ps -l -p 1810469

       F S   UID        PID       PPID  C PRI  NI ADDR    SZ WCHAN TTY          TIME CMD

00000200 -   100    1810469    1355809  -  16   0    -  568K -     ?        00:00:00 ./test_proc.out

Также существуют инструменты контроля и изменения самой политики планирования. К ним относятся функции получения сведений о предельных значениях приоритета при разных политиках: sched_get_priority_min(), sched_get_priority_max().

Программа getp3.c:

#include <stdio.h>

#include <sched.h>

#include <stdio.h>

main(int argc, char* argv[]){

       printf("Policies     MinPrio     MaxPrio\n");

       printf("FIFO    %12i%12i\n",sched_get_priority_min(SCHED_FIFO),sched_get_priority_max(SCHED_FIFO));

       printf("RR      %12i%12i\n",sched_get_priority_min(SCHED_RR),sched_get_priority_max(SCHED_RR));

       printf("OTHER   %12i%12i\n",sched_get_priority_min(SCHED_OTHER),sched_get_priority_max(SCHED_OTHER));

       printf("SPORADIC%12i%12i\n",sched_get_priority_min(SCHED_SPORADIC),sched_get_priority_max(SCHED_SPORADIC));

}

Результат ее работы:

$ cc -o getp3.out getp3.c

$ ./getp3.out

Policies     MinPrio     MaxPrio

FIFO               1          63

RR                 1          63

OTHER              1          63

SPORADIC           1          63

8. Приоритетность родственных процессов

Когда речь заходит о планировании, возникает вопрос, какой из процессов назначать на выполнении при равенстве их приоритетов. Рассмотрим пример того, как эта проблема решается при одновременной работе нескольких процессов:

Программа forks.c:

#include <sys/types.h>

#include <process.h>

#include <stdio.h>

#include <stdlib.h>

main(){

  if(!fork()){

    if(!fork()){

      if(!fork()){

        printf("I'm process  #4, my PID is %i, PPID is %i\n", getpid(),getppid());

      exit(0);

      }

      else{

        printf("I'm process  #3, my PID is %i, PPID is %i\n", getpid(),getppid());

        exit(0);

      }

    }

    else{

      printf("I'm process  #2, my PID is %i, PPID is %i\n", getpid(),getppid());

      exit(0);

    } 

  }

  else{

    printf("I'm process  #1, my PID is %i, PPID is %i\n", getpid(),getppid());

    exit(0);

  }

}

Результат выполнения:

$ ./forks.out

I'm process  #2, my PID is 659492, PPID is 655395

I'm process  #3, my PID is 659493, PPID is 659492

I'm process  #4, my PID is 659494, PPID is 659493

I'm process  #1, my PID is 655395, PPID is 532514

Как можно видеть, предпочтение отдается наиболее старшему процессу.

9. Выводы

При выполнении данной работы я ознакомился с организацией многозадачности в ОС QNX на примере различных средств контроля и управления. Можно выделить следующие основные классы рассмотренных задач:

Похожие материалы

Информация о работе