Відмінності між версіями «Тема 13. Моделювання станів процесів в Windows»
(не показані 2 проміжні версії цього учасника) | |||
Рядок 2: | Рядок 2: | ||
=new= | =new= | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
#include <windows.h> | #include <windows.h> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
DWORD ThreadProc (LPVOID lpdwThreadParam ); | DWORD ThreadProc (LPVOID lpdwThreadParam ); | ||
− | // | + | //оголошення глобальної змінної , видимої всіма потоками |
int nGlobalCount = 0; | int nGlobalCount = 0; | ||
− | // | + | //головна функція яка стартує всі інші потоки |
int __cdecl main( int argc, char **argv) | int __cdecl main( int argc, char **argv) | ||
{ | { | ||
− | int i, nThreads = 5; | + | int i, nThreads = 5;//кількість потоків що будуть створені |
DWORD dwThreadId; | DWORD dwThreadId; | ||
− | // | + | //Визначаємо кількість потоків, які будемо створювати |
if (argc > 1) { | if (argc > 1) { | ||
nThreads = atoi( argv[1]); | nThreads = atoi( argv[1]); | ||
} | } | ||
− | // | + | //Присвоюємо загальну кількість змінній кількості потоків |
nGlobalCount = nThreads; | nGlobalCount = nThreads; | ||
− | // | + | //Стартуємо нові потоки в циклі |
for (i=1; i<= nThreads; i++) { | for (i=1; i<= nThreads; i++) { | ||
//printf("i - %d\n",i); | //printf("i - %d\n",i); | ||
− | if (CreateThread(NULL, // | + | if (CreateThread(NULL, //1 Встановлюємо параметр безпеки дефолтним значенням |
− | 0, // | + | 0, //Розміп стеку потоку також залишаємо за замовчуванням |
(LPTHREAD_START_ROUTINE)&ThreadProc, | (LPTHREAD_START_ROUTINE)&ThreadProc, | ||
− | // | + | //Далі йдуть команди ініціалізації потоку |
− | (LPVOID) &i, // | + | (LPVOID) &i, //Запам"ятовуємо параметр потоку |
− | 0, // | + | 0, //і одразу ж запускаємо потік |
− | &dwThreadId // | + | &dwThreadId // Id потоку |
) == NULL) | ) == NULL) | ||
− | { | + | {//в разі помилки створення потоку виводимо повідомлення користувачеві |
printf("Error Creating Thread#: %d\n",i); | printf("Error Creating Thread#: %d\n",i); | ||
− | return(1); | + | return(1);//і завершуємо програму |
} | } | ||
else | else | ||
{ | { | ||
− | printf("Global Thread Count: %d %d %d\n", nGlobalCount, nThreads, i); | + | printf("Global Thread Count: %d %d %d\n", nGlobalCount, nThreads, i);//підсумкові інформація про створені потоки |
Sleep(1000); | Sleep(1000); | ||
} | } | ||
Рядок 46: | Рядок 43: | ||
return 0; | return 0; | ||
} | } | ||
− | // | + | //власна функція для роботи з потоком |
− | DWORD ThreadProc (LPVOID lpdwThreadParam ) | + | DWORD ThreadProc (LPVOID lpdwThreadParam ) |
{ | { | ||
− | // | + | //виводимо номер потоку |
printf ("Thread #: %d\n", *((int*)lpdwThreadParam)); | printf ("Thread #: %d\n", *((int*)lpdwThreadParam)); | ||
− | // | + | //зменшення лічильника |
nGlobalCount--; | nGlobalCount--; | ||
− | // | + | //завершення роботи потоку |
return 0; | return 0; | ||
} | } | ||
+ | |||
+ | Програма моделює створення нового потоку. Для створення нового потоку викликаємо системну функцію CreateThread (1). | ||
=ready= | =ready= | ||
− | |||
− | |||
#include <iostream> | #include <iostream> | ||
#include <windows.h> | #include <windows.h> | ||
Рядок 66: | Рядок 63: | ||
{ | { | ||
std::cout << "Message 1\n" ; | std::cout << "Message 1\n" ; | ||
− | Sleep(2000); // | + | Sleep(2000); //1: число в мілісекундах . 1 секунда = 1000 мілісекунд |
std::cout << "Message 2 a two seconds after Message 1" ; | std::cout << "Message 2 a two seconds after Message 1" ; | ||
return 0; | return 0; | ||
} | } | ||
+ | |||
+ | Ця програма створює потік , що примушує програму стати unrunnable на час інтервалу на підставі виклику функції Sleep(1). Системний годинник "цокає" з постійною швидкістю. Після того як інтервал очікування пройшов , потік готовий до роботи. Якщо вказати 0 мілісекунд , потік поступиться рештою свого часового строку, але як і раніше буде готовий. Зверніть увагу , що виконання готового потоку не гарантується відразу. Отже , потік не може не працювати , поки через деякий час після інтервалу закінчиться очікування . | ||
=running= | =running= | ||
Рядок 83: | Рядок 82: | ||
{ | { | ||
double dif=0; | double dif=0; | ||
− | while(1) | + | while(1)//1 |
{ | { | ||
− | dif+=1; | + | dif+=1;//2 |
} | } | ||
getch(); | getch(); | ||
return 0; | return 0; | ||
} | } | ||
+ | |||
+ | Потік у даному стані є потоком виконання. Виконання потоку легко забезпечити за допомогою безперервного цикла (1) і певних дій (2) в його тілі. | ||
=terminated= | =terminated= | ||
− | |||
− | |||
#include <time.h> | #include <time.h> | ||
#include <conio.h> | #include <conio.h> | ||
Рядок 100: | Рядок 99: | ||
#include <string> | #include <string> | ||
#include <windows.h> | #include <windows.h> | ||
− | #define timer 5.0 | + | #define timer 5.0//1 |
using namespace std; | using namespace std; | ||
int main() | int main() | ||
Рядок 106: | Рядок 105: | ||
double dif=0; | double dif=0; | ||
time_t start,end; | time_t start,end; | ||
− | time(&start); | + | time(&start);//2 |
string s; | string s; | ||
− | while(dif<timer) // | + | while(dif<timer) //Інціалізація зворотнього відліку |
{ | { | ||
printf("Type a word after %.0lf seconds..\nYour Time starts in..\n",timer); | printf("Type a word after %.0lf seconds..\nYour Time starts in..\n",timer); | ||
time (&end); | time (&end); | ||
− | dif = difftime(end,start); | + | dif = difftime(end,start);//обчислення часу що залишився до кінця зворотного відліку |
− | printf( "%.0lf seconds\n", timer-dif); | + | printf( "%.0lf seconds\n", timer-dif);//скільки секунд залишилося |
− | Sleep(1000); | + | Sleep(1000);//системна затримка |
− | system("CLS"); | + | system("CLS");//очистка екрану |
} | } | ||
− | HANDLE h_to_console=GetStdHandle( STD_INPUT_HANDLE ); | + | HANDLE h_to_console=GetStdHandle( STD_INPUT_HANDLE );//визначання контектсу вводу (простіше кажучи консолі) |
− | FlushConsoleInputBuffer(h_to_console); | + | FlushConsoleInputBuffer(h_to_console);//перенаправлення потоку виводу на цю консоль |
− | cout<<"Enter the String:\n"; | + | cout<<"Enter the String:\n";//3 |
cin>>s; | cin>>s; | ||
cout<<"You have Entered: "<<s; | cout<<"You have Entered: "<<s; | ||
− | getch(); | + | getch();//затримка еурану - щоб можна було отримати результат |
return 0; | return 0; | ||
} | } | ||
+ | |||
+ | Ідея полягає в тому щоб примусити Консоль чекати 'T' секунд для входу (1). Ця програма має таймер зворотного відліку (2). Після зворотного відліку починається введення сесія (3). | ||
=waiting= | =waiting= | ||
Рядок 139: | Рядок 140: | ||
string s; | string s; | ||
cout<<"Enter the String:\n"; | cout<<"Enter the String:\n"; | ||
− | cin>>s; | + | cin>>s;//1 |
cout<<"You have Entered: "<<s; | cout<<"You have Entered: "<<s; | ||
getch(); | getch(); | ||
return 0; | return 0; | ||
} | } | ||
+ | |||
+ | Потік стає потоком очікування , коли очікує на певну подію, дані, тощо. У нашому випадку програма чекає на введення користувачем текстового рядка (1). |
Поточна версія на 21:36, 13 грудня 2013
Ця стаття допоможе студентам при виконанні даної лабораторної роботи. Стаття написана з власного досвіду. Сьогодні ми будемо моделювати стани процесів в Windows з допомогою мови програмування С++ - всього їх розглянемо 5. Нам знадобляться Dev-C++ для компіляції програм і ProcessHacker для їх моніторингу. Рядки вихідного коду програм мають нумерацію, що дозволить давати коментарі щодо загальних принципів роботи програм. Ці коментарі знаходятся у тому ж розділі статті, що і відповідний лістинг. На початку коментаря в дужках вказано номер рядка, до якого цей коментар стосується. У ProcessHacker різні типи потоків підсвічуються різними кольорами - якому кольору відповідає який тип, можна з"ясувати в налаштуваннях програми. Отже, до справи!
new
#include <windows.h> #include <stdio.h> #include <stdlib.h> DWORD ThreadProc (LPVOID lpdwThreadParam ); //оголошення глобальної змінної , видимої всіма потоками int nGlobalCount = 0; //головна функція яка стартує всі інші потоки int __cdecl main( int argc, char **argv) { int i, nThreads = 5;//кількість потоків що будуть створені DWORD dwThreadId; //Визначаємо кількість потоків, які будемо створювати if (argc > 1) { nThreads = atoi( argv[1]); } //Присвоюємо загальну кількість змінній кількості потоків nGlobalCount = nThreads; //Стартуємо нові потоки в циклі for (i=1; i<= nThreads; i++) { //printf("i - %d\n",i); if (CreateThread(NULL, //1 Встановлюємо параметр безпеки дефолтним значенням 0, //Розміп стеку потоку також залишаємо за замовчуванням (LPTHREAD_START_ROUTINE)&ThreadProc, //Далі йдуть команди ініціалізації потоку (LPVOID) &i, //Запам"ятовуємо параметр потоку 0, //і одразу ж запускаємо потік &dwThreadId // 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; } //власна функція для роботи з потоком DWORD ThreadProc (LPVOID lpdwThreadParam ) { //виводимо номер потоку printf ("Thread #: %d\n", *((int*)lpdwThreadParam)); //зменшення лічильника nGlobalCount--; //завершення роботи потоку return 0; }
Програма моделює створення нового потоку. Для створення нового потоку викликаємо системну функцію CreateThread (1).
ready
#include <iostream> #include <windows.h> int main () { std::cout << "Message 1\n" ; Sleep(2000); //1: число в мілісекундах . 1 секунда = 1000 мілісекунд std::cout << "Message 2 a two seconds after Message 1" ; return 0; }
Ця програма створює потік , що примушує програму стати unrunnable на час інтервалу на підставі виклику функції Sleep(1). Системний годинник "цокає" з постійною швидкістю. Після того як інтервал очікування пройшов , потік готовий до роботи. Якщо вказати 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).