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

Матеріал з Вікі ЦДУ
Перейти до: навігація, пошук
 
(не показані 2 проміжні версії цього учасника)
Рядок 2: Рядок 2:
  
 
=new=
 
=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 <windows.h>
 
  #include <stdio.h>
 
  #include <stdio.h>
 
  #include <stdlib.h>
 
  #include <stdlib.h>
 
  DWORD ThreadProc (LPVOID lpdwThreadParam );
 
  DWORD ThreadProc (LPVOID lpdwThreadParam );
  //Global variable Shared by all threads
+
  //оголошення глобальної змінної , видимої всіма потоками
 
  int nGlobalCount = 0;
 
  int nGlobalCount = 0;
  //Main function which starts out each thread
+
  //головна функція яка стартує всі інші потоки
 
  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;
  //Determine the number of threads to start
+
  //Визначаємо кількість потоків, які будемо створювати
 
  if (argc > 1) {
 
  if (argc > 1) {
 
  nThreads = atoi( argv[1]);
 
  nThreads = atoi( argv[1]);
 
  }
 
  }
  //Set the global count to number of threads
+
  //Присвоюємо загальну кількість змінній кількості потоків
 
  nGlobalCount = nThreads;
 
  nGlobalCount = nThreads;
  //Start the threads
+
  //Стартуємо нові потоки в циклі
 
  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, //Choose default security
+
  if (CreateThread(NULL, //1 Встановлюємо параметр безпеки дефолтним значенням
  0, //Default stack size
+
  0, //Розміп стеку потоку також залишаємо за замовчуванням
 
  (LPTHREAD_START_ROUTINE)&ThreadProc,
 
  (LPTHREAD_START_ROUTINE)&ThreadProc,
  //Routine to execute
+
  //Далі йдуть команди ініціалізації потоку
  (LPVOID) &i, //Thread parameter
+
  (LPVOID) &i, //Запам"ятовуємо параметр потоку
  0, //Immediately run the thread
+
  0, //і одразу ж запускаємо потік
  &dwThreadId //Thread Id
+
  &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;
 
  }
 
  }
  //Thread Routine
+
  //власна функція для роботи з потоком
  DWORD ThreadProc (LPVOID lpdwThreadParam )  
+
  DWORD ThreadProc (LPVOID lpdwThreadParam )
 
  {
 
  {
  //Print Thread Number
+
  //виводимо номер потоку
 
  printf ("Thread #: %d\n", *((int*)lpdwThreadParam));
 
  printf ("Thread #: %d\n", *((int*)lpdwThreadParam));
  //Reduce the count
+
  //зменшення лічильника
 
  nGlobalCount--;
 
  nGlobalCount--;
  //ENd of thread
+
  //завершення роботи потоку
 
  return 0;
 
  return 0;
 
  }
 
  }
 +
 +
Програма моделює створення нового потоку. Для створення нового потоку викликаємо системну функцію CreateThread (1).
  
 
=ready=
 
=ready=
  
//This function causes a thread to relinquish the remainder of its time slice and become unrunnable for an interval based on the value of dwMilliseconds. The system clock "ticks" at a constant rate. If dwMilliseconds is less than the resolution of the system clock, the thread may sleep for less than the specified length of time. If dwMilliseconds is greater than one tick but less than two, the wait can be anywhere between one and two ticks, and so on. To increase the accuracy of the sleep interval, call the timeGetDevCaps function to determine the supported minimum timer resolution and the timeBeginPeriod function to set the timer resolution to its minimum. Use caution when calling timeBeginPeriod, as frequent calls can significantly affect the system clock, system power usage, and the scheduler. If you call timeBeginPeriod, call it one time early in the application and be sure to call the timeEndPeriod function at the very end of the application.
 
//After the sleep interval has passed, the thread is ready to run. If you specify 0 milliseconds, the thread will relinquish the remainder of its time slice but remain ready. Note that a ready thread is not guaranteed to run immediately. Consequently, the thread may not run until some time after the sleep interval elapses.
 
 
  #include <iostream>
 
  #include <iostream>
 
  #include <windows.h>
 
  #include <windows.h>
Рядок 66: Рядок 63:
 
  {
 
  {
 
     std::cout << "Message 1\n" ;
 
     std::cout << "Message 1\n" ;
     Sleep(2000);                    // number is in milliseconds 1Sec = 1000 MiliSeconds
+
     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=
  
//To make the Console wait for 't' seconds for an input
 
//This program has a countdown timer. After the countdown gets over, the input session starts.
 
 
  #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) //Countdown before starting
+
  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).