Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка по лекциям.doc
Скачиваний:
32
Добавлен:
20.09.2019
Размер:
1.52 Mб
Скачать

8.4. Приостановка и повторный запуск нити

Для нитей существует один вид системного действия, аналогов которому нет для процессов в операционных системах Windows и OS/2. Это – приостановка и повторный запуск отдельной нити. По смыслу действия одна из нитей процесса отдает приказ на приостановку другой нити этого же процесса. Приостановить нить другого процесса программным приказом невозможно (так как в подобном действии при внимательном анализе нет никакого практического смысла).

В операционной системе Unix для приостановки отдельной нити можно и нужно использовать уже знакомую читателю функцию pthread_kill со вторым параметром, задаваемым символической константой SIGSTOP, а для возобновления работы нити - ту же функцию, но уже с параметром SIGCONT. Следующий пример, представленный программой в листинге 8.4.1, демонстрирует приостановки и возобновление работы отдельной нити в операционной системе Unix, поддерживающей стандарт POSIX.

#include <pthread.h>

#include <stdio.h>

#include <signal.h>

char lbuk[ ]="abcdefghijklmnoprstuwxyz";

pthread_t tid1, tid2, tid3;

void procthread1(void *arg)

{int k, j;

for (k=0; k<24; k++)

{printf("\033[%02d;20H",k+1);

printf("\033[1;34m");

for (j=0; j<(int)arg; j++)

printf("%c",lbuk[k]);

if (k= =5) {pthread_kill(tid2, SIGSTOP);

printf("-Suspend thread2");}

if (k= =11) {pthread_kill(tid2, SIGCONT);

printf("-Resume thread2");}

printf("\n"); usleep(800000);

}

}

void procthread2(void *arg)

{int k, j;

for (k=0; k<24; k++)

{printf("\033[%02d;40H",k+1);

printf("\033[1;32m");

for (j=0; j<(int)arg; j++)

printf("%c",lbuk[k]);

usleep(1300000);

}

}

void procthread3(void *arg)

{int k, j;

for (k=0; k<24; k++)

{printf("\033[%02d;60H",k+1);

printf("\033[1;31m");

for (j=0; j<(int)arg; j++)

printf("%c",lbuk[k]);

printf("\n");

usleep(1100000);

}

}

int main()

{int k;

int rc;

printf("\033[2J\n");

rc=pthread_create(&tid1, NULL, (void*)procthread1, (void*)2);

rc=pthread_create(&tid2, NULL, (void*)procthread2, (void*)3);

rc=pthread_create(&tid3, NULL, (void*)procthread3, (void*)4);

for (k=0; k<24; k++)

{printf("\033[%02d;1H",k+1); printf("\033[1;37m");

printf("%c++",lbuk[k]);

printf("\n"); usleep(1000000);

}

pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL);

printf("\033[0m");

return 0;

}

Листинг 8.4.1. Программа с приостановкой нитей для Unix

В этой программе первая нить на 5-м шаге своей работы отдает приказ приостановки второй нити (идентификатор которой в tid2). Второй нитью мы здесь называем нить с идентификатором tid2, работающую на основе процедуры procthread2, а главную нить условно считаем нулевой. Приказ такой приостановки выдается в виде

pthread_kill(tid2, SIGSTOP).

Сама первая нить после такого приказа продолжает работать, а вторая, как легко наблюдать на экране по выводимым результатам, временно ничего не выводит, будучи приостановленной. Далее на 11-м шаге работы первой нити – в процедуре procthread1 вызывается функция возобновления работы приостановленной второй нити. Эта функция в программе присутствует в виде pthread_kill(tid2, SIGCONT). После ее выполнения, как можно наблюдать по выводу процесса, который работает по программе из листинга 8.4.1, вторая нить продолжает свой вывод, а следовательно, работает дальше. Небольшие дополнения в программе относительно ее аналога в листинге 8.2.1 осуществляют поясняющий вывод в ходе ее выполнения и предназначены для наглядности наблюдаемого процесса.

Программные средства для приостановки и возобновления нитей в операционных системах типа Windows состоят из двух функций ResumeThread и SuspendThread. Обе они имеют единственный аргумент – хэндл нити, на которую они должны подействовать – приостановить или возобновить ее работу. Прототипы этих функций описываются в виде:

DWORD SuspendThread(HANDLE hthread);

DWORD ResumeThread(HANDLE hthread).

Использование этих функций не имеет никаких особенностей в сравнении с другими рассмотренными операционными системами. В листинге 8.4.2 приведены фрагменты программы, отсутствующие части которой должны быть взяты из листинга 8.2.2 (начальная часть, тексты процедур procthread1, procthread2 и опущенные детали остальных). Эта программа создает три нити, кроме главной, и в ходе их работы в одной из них (третьей по условному счету) приостанавливает работу первой из них. Затем через несколько шагов внутреннего цикла в процедуре третьей нити отдается приказ на возобновление работы приостановленной ранее нити.

#include <windows.h>

#include <process.h>

. . .

DWORD WINAPI procthread3(void *arg)

{int k, j;

COORD pos;

for (k=0; k<24; k++) {

. . .

for (j=0; j<(int)arg; j++) printf("%c",lbuk[k]);

if (k==5)

{SuspendThread(hthread1);

pos.X=50; pos.Y=k+1; SetConsoleCursorPosition(hstdout,pos);

printf("Suspend thread1 into step=5");

}

if (k==16)

{ResumeThread(hthread1);

pos.X=50; pos.Y=k+1; SetConsoleCursorPosition(hstdout,pos);

printf("Resume thread1 into step=16");

}

. . .

Sleep(1000);

}

}

void main()

{unsigned long threadid1, threadid2, threadid3;

int k;

COORD pos;

hstdout=GetStdHandle(STD_OUTPUT_HANDLE);

. . .

for (k=0; k<24; k++) {

. . .

printf("%c++",lbuk[k]);

if (k==9)

{TerminateThread(hthread2, 0);

pos.X=1; pos.Y=k+1; SetConsoleCursorPosition(hstdout,pos);

printf("Kill thread2");

}

LeaveCriticalSection(&csec);

Sleep(1500);

}

. . .

CloseHandle(hthread1); CloseHandle(hthread2); CloseHandle(hthread3);

}

Листинг 8.4.2. Фрагменты программа с уничтожением нитей для Windows

Заметим, что в программе для управления поведением нитей используются их хэндлы, но никак не используются идентификаторы нитей. Практически в Windows всегда заметна некоторая избыточность средств, которая частично оправдывается большой суммарной сложностью системы.