2009-08-03 6 views
18
#include <stdio.h> 

int main() { 
    while(!DONE) { 
    /* check for stuff */ 
    } 
    return 0; 
} 

Powyższy przykładowy kod wykorzystuje 100% procesora do momentu, gdy DONE jest prawdziwe. Jak mogę zaimplementować program, który zapętla się i kończy się dopiero po WYKONANIU, ale który nie używa 100% procesora? Współczesne języki używają czegoś takiego jak App.ProcessMessages lub coś w tym stylu, aby dać OS sterowanie na chwilę, a następnie wrócić do pętli.C Pętla główna bez 100% cpu

Jestem nowy na C, oczywiście ... przy użyciu najnowszych GCC, Linux i Windows (przenośnym rozwiązaniem byłoby świetnie!)

+8

Należy używać obiekt synchronizacji, jeden, że można czekać aż zostanie on zasygnalizował, że sposób, w jaki nie zużywają CPU w ogóle. –

+2

Co to jest "DONE" i co spowoduje, że będzie niezerowe? Przypuszczalnie sensowne jest kontynuowanie przetwarzania, dopóki "check for stuff" nie oceni czegoś, co ustawia DONE jako niezerowe? –

+0

Lasse V. Karlsen: Twoje rozwiązanie wydaje się mieć sens (prawdopodobnie ma to sens, ale po prostu nie mam tej wiedzy). Czy mógłbyś rozwinąć? Czy powinienem badać wątki? (przykład może być miły) Charles Bailey: DONE powinno być int (wykonane zamiast DONE) i zostanie ustawione na 1, gdy użytkownik zrezygnował z aplikacji, na przykład. Przepraszam, jeśli nie potrafię się dobrze wytłumaczyć ... – pwseo

Odpowiedz

16

To zależy od tego, co chcesz zrobić w tej pętli.

Jeśli czekasz w pętli (np. Naciśnięcie klawisza {zrobienie czegoś} to twój mechanizm będzie marnować zasoby systemowe, nie dając nic w zamian.Odrobniony procesor po prostu zrobi więcej wolnych pętli.Może to zostać rozwiązane przez oczekiwanie na zdarzenia Nie po prostu spać, ale najlepiej zdarzenie, które wyzwala, że ​​coś znaczącego można zrobić.Na przykład, operacja na plikach (stdin jest również plikiem) byłaby przenośnym mechanizmem, który ustąpi innym aplikacjom, dopóki dane nie będą dostępne. bardziej szczegółowe może wymagać zanurzenia się w semafory lub sygnały, które są często zależne od systemu operacyjnego. Warstwa abstrakcji może rozwiązać ten problem:

Jeśli robisz coś użytecznego (np. przetwarzasz dużo danych), to 100% obciążenie procesora właśnie oznacza, że ​​procesor to my w najbardziej efektywny sposób. Możesz polegać na systemie operacyjnym, aby ustąpić miejsca innym i prawdopodobnie priorytetowym zadaniom.

Użycie funkcji takiej jak uśpienie spowoduje obniżenie zużycia procesora, ale aplikacja będzie wolniejsza. Będzie to wymagało uzyskania kompromisu pomiędzy akceptowalną wydajnością a obciążeniem procesora. Maksymalna prędkość wykonania zostanie określona przez parametr spania, a nie przez prędkość procesora. Ponadto, jeśli problem dotyczy zasilania (to znaczy czasu pracy na baterii), będzie to wymagało przebudzenia procesora (koniec okresu snu) bez żadnej pracy; to jest inne marnowanie zasobów systemowych.

+0

Chyba będę musiał nauczyć się semaforów i sygnałów, a następnie Jakieś szczegółowe wskazówki na ten temat? :) – pwseo

+2

Jakie przetwarzanie znajduje się w pętli głównej? Wiadomości, sygnały, semafory są bardziej związane z systemem operacyjnym niż język, którego dotyczy. Na przykład http://www.ibm.com/developerworks/eserver/library/es-win32linux-sem.html pokazuje, jak obsługiwane są semafory w systemie Windows w porównaniu do systemu Linux. Jeśli potrzebujesz obsługi obu, możesz albo użyć POSIX (co jest opcjonalne dla Windows, tj. W cygwin) lub umieścić kod w module zależnym od platformy, który tworzysz dla każdego systemu operacyjnego. – Adriaan

1

użycie

uśpienia (int milisekundach)

+3

Argument spania to tak naprawdę liczba sekund, a nie milisekund. –

+1

Myślę, że to zależy od systemu operacyjnego ... podczas gdy masz rację, że parametr jest sekundowany pod Unix/Linux/* BSD, myślę, że pamiętam, że jest to milisekunda w systemie Windows ... Jednak minęły lata, więc mogłem być w błędzie ... – Nicolas

+5

sleep() zajmuje liczbę sekund. usleep() (BSD i POSIX) zajmuje mikrosekundy. nanosleep() (również POSIX) zajmuje nanosekundę. – qrdl

3

Co dokładnie to sprawdzasz?

Jeśli sprawdzasz coś niestabilnego, które zostało zmienione przez sprzęt lub inny proces, po prostu zadzwoń pod numer sleep w swojej pętli.

Jeśli czekasz na deskryptor pliku lub deskryptor gniazda sieciowego, będziesz chciał użyć w pętli select lub poll, aby czekać na deskryptor, aby dane były gotowe do użycia.

0

Użyj yield().

+0

To nie jest przenośne, ponieważ nie definiuje go ani standard C, ani POSIX. –

+1

Czy to nie wystarczyłoby innym procesom więcej czasu, ciągle zajmując cały czas, których inne procesy nie zużywają? – liori

0

Jeśli zgaduję poprawnie (nie wiem o tym), odpowiednik App.ProcessMessages robi blokowanie IO. A ponieważ nie znam żadnej implementacji C w wielozadaniowym systemie operacyjnym używającym odpytywania, każde standardowe C IO powinno być bezpieczne.

5

Twoje dwie opcje to odpytywanie i powiadomienie o zdarzeniu.

Przepytywanie będzie najłatwiejsze do zaprogramowania - w zasadzie masz wątek w stanie uśpienia przez krótki czas przy każdym przejściu przez pętlę. To zwalnia procesor do innych zadań. Wadą jest to, że w twoim kodzie "sprawdź za rzeczy" będzie opóźnienie - więc jeśli śpisz przez sekundę, może minąć nawet sekunda, zanim twój kod wykryje ten stan. Twój kod tutaj będzie łatwy do przeniesienia.

Inną opcją jest poczekanie na warunki warunkowe POSIX lub Windows lub coś w tym stylu. Nie tylko ten kod zostanie zmieniony, ale też "sprawdzane elementy" będą musiały wywołać flagę, aby powiedzieć, że jest zrobione. Byłby to nieco mniej przenośny kod, chociaż prawdopodobnie istnieją biblioteki, które pomijają platformę. Ale dostaniesz natychmiastowe wyniki na to wydarzenie i nie marnujesz czasu procesora na sprawdzanie rzeczy, których nie ma.

+1

+1 za sugerowanie użycia synchronizacji POSIX. –

9

Masz kilka możliwości:

  1. Używaj sleep(), aby wymusić proces okresowo wstrzymać i pozwolić inny proces użycie CPU
  2. Uruchom na poziomie niższym priorytecie - co spowoduje do systemu operacyjnego przypisać mniej czasu procesora
  3. Użyj muteksu lub innego obiektu do synchronizacji, aby wykryć, kiedy praca jest dostępna - co spowoduje, że proces nie zużyje czasu procesora, chyba że faktycznie wykonuje pracę
  4. Jeśli otrzymasz pracę szybciej niż możesz to przetworzyć - nadal możesz potrzebować u se jakiś model snu/priorytetu, aby całkowicie nie zużywać procesora.

Opcja nr 2 może być trudna do zrobienia w sposób neutralny dla platformy/OS. Najlepiej jest uruchomić proces i zmienić jego priorytet w środowisku wykonawczym.

0

W systemie Windows można użyć stanu uśpienia (w milisekundach) zdefiniowanego w pliku windows.h.

2

Jeśli dobrze zrozumiałem, powiedziałeś w komentarzach, że DONE można zmienić z innych wątków. Jeśli tak, zmienne warunkowe mają sens. Z pthreads, należałoby zrobić:

W wątku, który czeka:

pthread_mutex_lock(&mutex); 
while (!DONE) { 
    pthread_cond_wait(&cond, &mutex); 
} 
pthread_mutex_unlock(&mutex); 

W innych wątków, gdy skończysz zmieniany:

pthread_mutex_lock(&mutex); 
DONE = 1; 
pthread_cond_signal(&cond); 
pthread_mutex_unlock(&mutex); 
+0

Możesz odblokować wątek z innego wątku? – user457015