Win Api- wątki, priorytety, wątek główny

Win Api- wątki, priorytety, wątek główny
LU
  • Rejestracja:około 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:11
0

Cześć!
Napisałem sobie program, który:
Tworzy jakieś cztery wątki, przekazuje im po jednym argumencie (jakaś zmienna globalna) i po przeliczeniu do określonej liczby inkrementuje zmienną. W mainie wartości n1-n4 są wypisywane. Wszędzie są pętle nieskończone, poza mainem gdzie jest if(_kbhit()){3x getch, 'a' zawiesza wątki, 'z' wznawia a 'esc' kończy program}.

Chciałem zmienić priorytety wątków, tak żeby jeden był wysoki, a reszta niskie. Wtedy przecież powinno wykonywać program wątku o najwyższym priorytecie dopóki się on nie skończy? Więc powinno mi zwiększać tylko jedną zmienną, a cały czas idzie w takim samym tempie wszystko. [Kod dam niżej].

Pytanie 1: Myślałem, żeby stworzyć główny wątek przez CreateProcess i żeby to odpalało konsolę w której byłyby wyświetlane te zmienne. Chcąc żeby tamten wątek (główny) się konczył na klawisz esc (analogicznie jak wyżej, tylko zamiast w main'ie programu zrobić to w głównym wątku) to co trzeba zrobić? Stworzyć nowy typ wątku i tam to wszystko wrzucić?

Pytanie 2: Czy można przekazać większą ilość parametru do wątku? Np. numer wątku jako liczbę porządkową i zmienną do inkrementacji?

Kopiuj
 	HANDLE hw_1 = CreateThread(0, 0, watek, &n1, 0, 0);
	SetThreadPriority(hw_1, THREAD_PRIORITY_TIME_CRITICAL);
	HANDLE hw_2 = CreateThread(0, 0, watek, &n2, 0, 0);
	SetThreadPriority(hw_2, THREAD_PRIORITY_IDLE);
	HANDLE hw_3 = CreateThread(0, 0, watek, &n3, 0, 0);
	SetThreadPriority(hw_3, THREAD_PRIORITY_IDLE);
	HANDLE hw_4 = CreateThread(0, 0, watek, &n4, 0, 0);
	SetThreadPriority(hw_4, THREAD_PRIORITY_IDLE);
	while (1) {
		if (_kbhit()) {
			char c = _getch();
			if (c == 'a') {
				SuspendThread(hw_1);
				SuspendThread(hw_2);
				SuspendThread(hw_3);
				SuspendThread(hw_4);
			}
			else if (c == 'z') {
				ResumeThread(hw_1);
				ResumeThread(hw_2);
				ResumeThread(hw_3);
				ResumeThread(hw_4);
			}
			else if (c == 27)
				break;
		}
		Sleep(500);
		printf("n1: %d\nn2: %d\nn3: %d\nn4: %d\n\n", n1, n2, n3, n4);
	}
	TerminateThread(hw_1, 0);
	TerminateThread(hw_2, 0);
	TerminateThread(hw_3, 0);
	TerminateThread(hw_4, 0);
	CloseHandle(hw_1);
	CloseHandle(hw_2);
	CloseHandle(hw_3);
	CloseHandle(hw_4);
	HANDLE handle;
	handle = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
	TerminateProcess(handle, 0);
edytowany 2x, ostatnio: lukasson
NI
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Warszawa
  • Postów:535
0

możesz spakować do klasy kilka zmiennych i podawać obiekt do wątku


Programuje i programuje ,przychodzi człowiek "o niższej inteligencji" i rok pracy zmarnowany
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:dzień
1

Chciałem zmienić priorytety wątków, tak żeby jeden był wysoki, a reszta niskie. Wtedy przecież powinno wykonywać program wątku o najwyższym priorytecie dopóki się on nie skończy?

Skąd takie założenie? Zwłaszcza na wielordzeniowym procesorze masz praktycznie gwarancję, że tak nie będzie. Jeden rdzeń będzie przez większość czasu zajęty przez wątek time critical, ale reszta będzie wolna dla pozostałych.

Myślałem, żeby stworzyć główny wątek przez CreateProcess

CreateProcess tworzy całkiem nowy proces, a nie wątek. To znaczy że w nowym procesie tych zmiennych nie będzie, będą zupełnie nowe.

Czy można przekazać większą ilość parametru do wątku? Np. numer wątku jako liczbę porządkową i zmienną do inkrementacji?

Można przekazać wskaźnik do struktury. Pamiętaj że jeśli jeden wątek coś zapisuje by drugi to odczytał, potrzebne są metody typu InterlockedExchange i podobne.
A nawet jeśli można zagwarantować atomowość danej operacji bez nich, to wtedy potrzebne jest volatile przy zmiennej.

Pokaż cały kod - z funkcją watek().

W normalnym programie unikaj TerminateThread(). Wątek powinien się zakończyć od wewnątrz.

LU
  • Rejestracja:około 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:11
0

Skąd takie założenie? Zwłaszcza na wielordzeniowym procesorze masz praktycznie gwarancję, że tak nie będzie. Jeden rdzeń będzie przez większość czasu zajęty przez wątek time critical, ale reszta będzie wolna dla pozostałych.

No tak, masz rację, o tym nie pomyślałem. Tak samo jak o istnieniu Balance Set Menager, który i tak chroniłby pozostałe wątki przed zagłodzeniem.

CreateProcess tworzy całkiem nowy proces, a nie wątek. To znaczy że w nowym procesie tych zmiennych nie będzie, będą zupełnie nowe.

No właśnie, więc dlatego pytałem jak zrobić, żebym mógł stworzyć nowy proces który by te wątki obsługiwał. Chodzi mi o to, że chcę zrozumieć po co w praktyce może być funkcja CreateProcess(); i próbuję sobie tworzyć różne programy do napisania o tyle o ile.

Można przekazać wskaźnik do struktury. Pamiętaj że jeśli jeden wątek coś zapisuje by drugi to odczytał, potrzebne są metody typu InterlockedExchange i podobne.
A nawet jeśli można zagwarantować atomowość danej operacji bez nich, to wtedy potrzebne jest volatile przy zmiennej.

To jeszcze nazbyt do przodu, atomowe zmienne będą ale jeszcze nie teraz :).

W normalnym programie unikaj TerminateThread(). Wątek powinien się zakończyć od wewnątrz.

Więc mógłbym przerzucić getch'a do wątku i jezeli jest "esc" to tam dawać Terminate Thread()? To byłoby lepsze (i działające?) rozwiązanie?

Pokaż cały kod - z funkcją watek().

Kopiuj
 #include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <tchar.h>
#include <Psapi.h>

int n1 = 0;
int n2 = 0;
int n3 = 0;
int n4 = 0;

//TCHAR cmd[50] = L"cmd.exe";
unsigned long __stdcall watek(void* Param) {
	while (1) {
		for (int i = 0; i < 30000; i++);
		(*(int*)Param)++;
	}
	return 0;
}

int main()
{
	/*PROCESS_INFORMATION pi;
	STARTUPINFO si;

	ZeroMemory(&pi, sizeof(pi));
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	if (!CreateProcess(NULL,
		cmd,
		NULL,
		NULL,
		FALSE,
		0,
		NULL,
		NULL,
		&si,
		&pi))
	{
		printf("Could not create process. (%ld)", GetLastError());
		return 1;
	}
	THREAD_PRIORITY_TIME_CRITICAL
	THREAD_PRIORITY_HIGHEST
	THREAD_PRIORITY_ABOVE_NORMAL
	THREAD_PRIORITY_NORMAL
	THREAD_PRIORITY_BELOW_NORMAL
	THREAD_PRIORITY_LOWEST
	THREAD_PRIORITY_IDLE*/

	HANDLE hw_1 = CreateThread(0, 0, watek, &n1, 0, 0);
	SetThreadPriority(hw_1, THREAD_PRIORITY_TIME_CRITICAL);
	HANDLE hw_2 = CreateThread(0, 0, watek, &n2, 0, 0);
	SetThreadPriority(hw_2, THREAD_PRIORITY_IDLE);
	HANDLE hw_3 = CreateThread(0, 0, watek, &n3, 0, 0);
	SetThreadPriority(hw_3, THREAD_PRIORITY_IDLE);
	HANDLE hw_4 = CreateThread(0, 0, watek, &n4, 0, 0);
	SetThreadPriority(hw_4, THREAD_PRIORITY_IDLE);
	while (1) {
		if (_kbhit()) {
			char c = _getch();
			if (c == 'a') {
				SuspendThread(hw_1);
				SuspendThread(hw_2);
				SuspendThread(hw_3);
				SuspendThread(hw_4);
			}
			else if (c == 'z') {
				ResumeThread(hw_1);
				ResumeThread(hw_2);
				ResumeThread(hw_3);
				ResumeThread(hw_4);
			}
			else if (c == 27)
				break;
		}
		Sleep(500);
		printf("n1: %d\nn2: %d\nn3: %d\nn4: %d\n\n", n1, n2, n3, n4);
	}

	TerminateThread(hw_1, 0);
	TerminateThread(hw_2, 0);
	TerminateThread(hw_3, 0);
	TerminateThread(hw_4, 0);
	CloseHandle(hw_1);
	CloseHandle(hw_2);
	CloseHandle(hw_3);
	CloseHandle(hw_4);
	HANDLE handle;
	handle = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
	TerminateProcess(handle, 0);
	return 0;
}
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:dzień
1

No właśnie, więc dlatego pytałem jak zrobić, żebym mógł stworzyć nowy proces który by te wątki obsługiwał.

Nowy proces to nowy proces (program exe). Nie przenosi się wątków z jednego procesu do drugiego.
Jest możliwa komunikacja międzyprocesorowa, ale na razie zostaw to w spokoju.

Chodzi mi o to, że chcę zrozumieć po co w praktyce może być funkcja CreateProcess()

Żeby uruchomić nowy program.

To jeszcze nazbyt do przodu, atomowe zmienne będą ale jeszcze nie teraz :)

Nie ma "nie teraz". Robisz wątki, to ich synchronizacja musi być zrobiona prawidłowo.
Od razu, nie kiedyś tam. Wątki łatwe nie są.

Więc mógłbym przerzucić getch'a do wątku i jezeli jest "esc" to tam dawać Terminate Thread()? To byłoby lepsze (i działające?) rozwiązanie?

Raczej getcha w wątku głównym, potem zmiana jakiejś zmiennej np. volatile bool koniec, i okresowe jej sprawdzanie w pozostałych wątkach.

LU
  • Rejestracja:około 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:11
0
Kopiuj
#include "stdafx.h"
#include <Windows.h>
#include <mmsystem.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <tchar.h>
#include <Psapi.h>
volatile DWORD end;
int n1 = 0;
int n2 = 0;
int n3 = 0;
int n4 = 0;
struct param {
	const int number;
	int& n;
};
unsigned long __stdcall watek(void* Param) {
	DWORD kill = 0;
	while (1) {
		for (int i = 0; i < 30000; i++);
		(*(struct param*)Param).n++;
		InterlockedExchange(&kill, end);
		if (kill) {
			break;
		}
	}
	printf("Thread number %u terminate!\n", (*(struct param*)Param).number);
	TerminateThread(OpenProcess(PROCESS_TERMINATE, 0, GetCurrentThreadId()), 0);
	return 0;
}

int main()
{
	end = 0;
	struct param p = { 1, n1 };
	struct param p2 = { 2, n2 };
	struct param p3 = { 3, n3 };
	struct param p4 = { 4, n4 };
	HANDLE hw_1 = CreateThread(0, 0, watek, &p, 0, 0);
	SetThreadPriority(hw_1, THREAD_PRIORITY_TIME_CRITICAL);
	HANDLE hw_2 = CreateThread(0, 0, watek, &p2, 0, 0);
	SetThreadPriority(hw_2, THREAD_PRIORITY_IDLE);
	HANDLE hw_3 = CreateThread(0, 0, watek, &p3, 0, 0);
	SetThreadPriority(hw_3, THREAD_PRIORITY_IDLE);
	HANDLE hw_4 = CreateThread(0, 0, watek, &p4, 0, 0);
	SetThreadPriority(hw_4, THREAD_PRIORITY_IDLE);
	while (1) {
		if (_kbhit()) {
			char c = _getch();
			if (c == 'a') {
				SuspendThread(hw_1);
				SuspendThread(hw_2);
				SuspendThread(hw_3);
				SuspendThread(hw_4);
				printf("* * *All threads are suspended! * * *\n");
			}
			else if (c == 'z') {
				ResumeThread(hw_1);
				ResumeThread(hw_2);
				ResumeThread(hw_3);
				ResumeThread(hw_4);
				printf("* * *All threads are resumed! * * *\n");
			}
			else if (c == 27) {
				end = 1;
				break;
			}
		}
		Sleep(500);
		printf("n1: %d\nn2: %d\nn3: %d\nn4: %d\n\n", n1, n2, n3, n4);
	}
	WaitForSingleObject(hw_1, INFINITE);
	WaitForSingleObject(hw_2, INFINITE);
	WaitForSingleObject(hw_3, INFINITE);
	WaitForSingleObject(hw_4, INFINITE);
	CloseHandle(hw_1);
	CloseHandle(hw_2);
	CloseHandle(hw_3);
	CloseHandle(hw_4);
	HANDLE handle;
	handle = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
	TerminateProcess(handle, 0);
	return 0;
}

W ten sposób? Poprawnie rozumiem zasadę działania? Volatile daje to że nie jest sprawdzana wartość tylko rejestry przez co bierzemy dokładną wartość w danej chwili. Jak wcisnę ESC to zmieniam end = 1 i w wątku jest sprawdzana ta wartość- jeżeli jest 1 to przerywa pętlę nieskończoną, daje komunikat o zabiciu wątku i kończy wątek- program główny czeka na zakończenie. Potem dopiero zamyka uchwyty.

Jeżeli jest ok to jeszcze pytania:
Pytanie 1: Można jakoś sprawdzać czas oczekiwania na zasoby danego wątku?
Pytanie 2: Jakieś zadanie z funkcją timeGetTime()? Do czego ona się przydaje? Bo poza tym że zwraca czas w ms od momentu uruchomienia systemu i ma dokładkość do 1ms to nie wiem zbytnio po co to jest.
Pytanie 3: Chciałbym stworzyć strukturę z numerem wątku i tą liczbą n globalną- żeby przekazać do wątku. W jaki sposób to stworzyć? Struktura będzie:

Kopiuj
struct param{
int number;
int& n;
};

czyli tak jak w kodzie powyżej?

edytowany 1x, ostatnio: lukasson
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:dzień
0
Kopiuj
    TerminateThread(OpenProcess(PROCESS_TERMINATE, 0, GetCurrentThreadId()), 0);

Wyrzuć. Niech się funkcja po prostu zakończy.

Kopiuj
    HANDLE handle;
    handle = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
    TerminateProcess(handle, 0);

Jak wyżej.

Volatile daje to że nie jest sprawdzana wartość tylko rejestry przez co bierzemy dokładną wartość w danej chwili.

Nie. A nawet odwrotnie. volatile powoduje, że każdy zapis i odczyt zmiennej jest dokonywany w pamięci, i nie jest opóźniany ani pomijany.

Kopiuj
 Struktura będzie:

struct param{
int number;
int& n;
};

ta referencja to chyba nie jest dobry pomysł. pozbądź się tych n1, n2 i zostaw tylko struktury.

edytowany 1x, ostatnio: Azarien
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)