Тема 13. Моделювання станів процесів в Windows

Матеріал з Вікі ЦДУ
Перейти до: навігація, пошук

Ця стаття допоможе студентам при виконанні даної лабораторної роботи. Стаття написана з власного досвіду. Сьогодні ми будемо моделювати стани процесів в Windows з допомогою мови програмування С++ - всього їх розглянемо 5. Нам знадобляться Dev-C++ для компіляції програм і ProcessHacker для їх моніторингу. Рядки вихідного коду програм мають нумерацію, що дозволить давати коментарі щодо загальних принципів роботи програм. Ці коментарі знаходятся у тому ж розділі статті, що і відповідний лістинг. На початку коментаря в дужках вказано номер рядка, до якого цей коментар стосується. У ProcessHacker різні типи потоків підсвічуються різними кольорами - якому кольору відповідає який тип, можна з"ясувати в налаштуваннях програми. Отже, до справи!

new_

//Closing the handle before the thread procedure returns
//I have heard of this being done, although this page doesn't seem to mention if it's valid to do such a thing. I've even heard of those that call CloseHandle() 
//on the thread handle immediately after creating the thread. So what's the deal here?Yes, you can close the thread handle immediately, the thread object will exist until all handles are closed and the thread has terminated. 
//Closing the handles before the thread terminates isn't explicitely allowed here - but also not explicitely forbidden, and numerous samples make use of these "one-shot threads". (ph)
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
DWORD ThreadProc (LPVOID lpdwThreadParam );
//Global variable Shared by all threads
int nGlobalCount = 0;
//Main function which starts out each thread
int __cdecl main( int argc, char **argv)
{ 
int i, nThreads = 5;
DWORD dwThreadId;
//Determine the number of threads to start
if (argc > 1) {
nThreads = atoi( argv[1]);
}
//Set the global count to number of threads
nGlobalCount = nThreads;
//Start the threads
for (i=1; i<= nThreads; i++) {
//printf("i - %d\n",i);
if (CreateThread(NULL, //Choose default security
0, //Default stack size
(LPTHREAD_START_ROUTINE)&ThreadProc,
//Routine to execute
(LPVOID) &i, //Thread parameter
0, //Immediately run the thread
&dwThreadId //Thread Id
) == NULL)
{
printf("Error Creating Thread#: %d\n",i);
return(1);
}
else
{
printf("Global Thread Count: %d %d %d\n", nGlobalCount, nThreads, i);
Sleep(1000);
}
}
return 0;
}
//Thread Routine
DWORD ThreadProc (LPVOID lpdwThreadParam ) 
{
//Print Thread Number
printf ("Thread #: %d\n", *((int*)lpdwThreadParam));
//Reduce the count
nGlobalCount--;
//ENd of thread
return 0;
}

ready_

#include <iostream>
#include <windows.h>
int main ()
{
    std::cout << "Message 1\n" ;
    Sleep(2000);                     // число в мілісекундах . 1 секунда = 1000 мілісекунд
    std::cout << "Message 2 a two seconds after Message 1" ;
   return 0;
}

Потік Ця функція викликає потік , що примушує програму стати unrunnable для інтервалу на підставі значення dwMilliseconds . Системний годинник "цокає" з постійною швидкістю. Якщо dwMilliseconds менше , ніж значення системних годин ,потік може спати менше , ніж певний час. Якщо dwMilliseconds більше, ніж один тік але менше двох , очікування може бути в будь-якому місці від одного до двох тіків, і так далі. Для підвищення точності інтервалу сну , викличте функцію timeGetDevCaps визначити підтримуваний мінімальний дозвіл таймера і функцію timeBeginPeriod для установки дозволу таймера до мінімуму . Будьте обережні при виклику timeBeginPeriod ,так як часті дзвінки можуть істотно вплинути на системний годинник і планувальник. Якщо ви викликаєте timeBeginPeriod , оголосимо його один раз на початку застосування і обов'язково треба викликати функцію timeEndPeriod в самому кінці програми.

Після того як інтервал очікування пройшов , потік готовий до роботи. Якщо вказати 0 мілісекунд , потік поступиться решту свого часового строку, але як і раніше буде готовий. Зверніть увагу , що виконання готового потоку не гарантується відразу. Отже , потік не може не працювати , поки через деякий час після інтервалу закінчиться очікування .

running

#include <time.h>
#include <conio.h>
#include <iostream>
#include <string>
#include <windows.h>
#define timer 5.0
using namespace std;
int main()
{
double dif=0;
while(1)//1
{
dif+=1;//2
}
getch();
return 0;
}

Потік у даному стані є потоком виконання. Виконання потоку легко забезпечити за допомогою безперервного цикла (1) і певних дій (2) в його тілі.

terminated

#include <time.h>
#include <conio.h>
#include <iostream>
#include <string>
#include <windows.h>
#define timer 5.0//1
using namespace std;
int main()
{
double dif=0;
time_t start,end;
time(&start);//2
string s;
while(dif<timer)	//Інціалізація зворотнього відліку
{
printf("Type a word after %.0lf seconds..\nYour Time starts in..\n",timer);
time (&end);
dif = difftime(end,start);//обчислення часу що залишився до кінця зворотного відліку
printf( "%.0lf seconds\n", timer-dif);//скільки секунд залишилося
Sleep(1000);//системна затримка
system("CLS");//очистка екрану
}
HANDLE h_to_console=GetStdHandle( STD_INPUT_HANDLE );//визначання контектсу вводу (простіше кажучи консолі)
FlushConsoleInputBuffer(h_to_console);//перенаправлення потоку виводу на цю консоль
cout<<"Enter the String:\n";//3
cin>>s;
cout<<"You have Entered: "<<s;
getch();//затримка еурану - щоб можна було отримати результат
return 0;
}

Ідея полягає в тому щоб примусити Консоль чекати 'T' секунд для входу (1). Ця програма має таймер зворотного відліку (2). Після зворотного відліку починається введення сесія (3).

waiting

#include <time.h>
#include <conio.h>
#include <iostream>
#include <string>
#include <windows.h>
#define timer 5.0
using namespace std;
int main()
{
string s;
cout<<"Enter the String:\n";
cin>>s;//1
cout<<"You have Entered: "<<s;
getch();
return 0;
}

Потік стає потоком очікування , коли очікує на певну подію, дані, тощо. У нашому випадку програма чекає на введення користувачем текстового рядка (1).