Monthly archive for May, 2008

Laboratoria kontra projekty

2008-05-17 15:41

Studia techniczne – a więc także i informatyka – różnią się od innych choćby tym, że tutaj nie obejdzie się bez dużej ilości zadań praktycznych. Brudzenie tablicy pyłem kredowym na wykładach i ćwiczeniach to bowiem za mało – zwłaszcza, jeśli mówimy o uczelniach technicznych, a nie uniwersytetach.
Mamy więc dwa dodatkowe rodzaje zajęć: laboratoryjne i projektowe. Oba mają na celu wykorzystanie zdobytej przez studenta wiedzy w praktyce oraz nabranie pewnej porcji doświadczenia. Cel chwalebny, wykonanie niestety nieco gorsze…

Dotyczy to głównie laboratoriów, które w pewnej formie są według mnie kompletnym nieporozumieniem, jeśli chodzi o większość dziedzin informatyki – zwłaszcza tych związanych bezpośrednio lub pośrednio z programowaniem. Zajęcia takie wyglądają mniej więcej tak: student otrzymuje takie-a-takie zadanie – którym jest zwykle napisanie programu – i do końca zajęć ma się z niego wywiązać, czyli rzeczony program napisać. Potem wyniki jego pracy są oceniane przez prowadzących.
W czym ta formuła jest zła? Ano można jej wytknąć całkiem sporo mankamentów:

  • Nieżyciowość. W pracy nikt przecież nie koduje na akord: wiadomo, że z ośmiogodzinnego dnia programista na efektywną pracę przeznacza najwyżej 4 do 5 godzin. Kogo zresztą byłoby stać na to, by każdy projekt rozparcelować na małe kawałki, które potem byłyby pisane przez koderów w ściśle określonych ramach czasowych? To zapewne całkowicie niemożliwe, a co najmniej wysoce nieopłacalne.
  • Złe nawyki. Jeśli mamy tylko godzinę lub dwie, by oddać działający kawałek kodu, na bardzo daleki plan schodzą takie kwestie jak jego czytelność, odpowiedni stopień nasycenia komentarzami, elastyczność, możliwość ponownego wykorzystania, i tak dalej. Krótko mówiąc, produkuje się wtedy kod “tylko do zapisu”, zgodnie z zasadą 3Z: Zakodź, Zalicz, Zapomnij :) Nabyte przy okazji przyzwyczajenia do programistycznego niechlujstwa mogą się odbijać czkawką jeszcze przez bardzo długi czas.
  • Stres. Takie laboratoria to tak naprawdę nic innego, jak kartkówka wklepywana na klawiaturze. Nie jest to nic przyjemnego i w (zbyt) dużych dawkach prawdopodobnie może nawet skutecznie odstręczyć od kodowania jako takiego.

W przeciwieństwie do laboratoriów, projekty właściwie nie mają wymienionych wyżej wad. Są też na pewno bardziej pouczające, szczególnie wtedy gdy należy je wykonywać w grupach. Zdobyte przy okazji doświadczenie jest z pewnością o wiele cenniejsze, bo obejmuje przecież także organizowanie pracy i planowanie kolejnych jej etapów. Czegoś takiego nie można raczej powiedzieć o zadaniach wykonywanych na szybko na laboratoriach.

Tags: ,
Author: Xion, posted under Studies, Thoughts » 16 comments

Triki z PowerShellem #1 – GUI

2008-05-15 14:41

Windows PowerShell jest oczywiście powłoką tekstową z wierszem poleceń. Wszystkie więc czynności, jakie możemy w nim wykonać, wiążą się z wpisywaniem tychże poleceń i odczytywaniem wyników, podawanych także w postaci tekstowej. Prosto, minimalistycznie i naturalnie.

I właśnie dlatego jednym z pierwszym eksperymentów, jakie przy użyciu tego narzędzia wykonałem, była… próba wyświetlenia okienka z GUI :) Najpierw miało to być skromne okienko komunikatu (message box), jednak szybko okazało, że nie będzie to wcale łatwe. Domyślnie w PowerShellu nie jest bowiem załadowane assembly System.Windows.Forms, które to jest niezbędnie potrzebne do zabawy z okienkami. Nie oznacza to na szczęście, że oprócz jego załadowania należy też korzystać z niewygodnego interfejsu refleksji, aby cokolwiek przy jego użyciu zrobić (np. stworzyć obiekt klasy i wywołać jego metodę). Wystarczy po prostu jedno wywołanie w stylu:

  1. [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
  2. # Od .NET 2.0 ta metoda jest deprecated, ale tutaj nam to chwilowo nie przeszkadza ;-)

Okno komunikatu w PowerShellui od tej pory można już zupełnie normalnie korzystać z Windows.Forms… No, prawie. Możemy w każdym razie uraczyć się okienkiem komunikatu:

  1. [System.Windows.Forms.MessageBox]::Show("Hello world!", "Message",
  2.     [Windows.Forms.MessageBoxButtons]::OK,
  3.     [Windows.Forms.MessageBoxIcon]::Information)

A gdy już na nie popatrzymy, to pewnie zechcemy też czegoś więcej – na przykład “prawdziwego” okna, czyli zwykłej formy. To także jest do zrobienia:

  1. $form = New-Object System.Windows.Forms.Form
  2. $form.Text = "GUI!"
  3. [System.Windows.Forms.Application]::Run($form)

Bez większego problemu można by zresztą dodać do formy kontrolki potomne, jak przyciski czy pola tekstowe… Jest jednak jeden poważny problem: właściwie nie ma sposobu na podpięcie pod nasze kontrolki procedur zdarzeniowych – nawet mimo tego, że przy użyciu wyjątkowo perfidnej sztuczki da się w PowerShellu tworzyć delegaty. Stworzone okienka pozostaną więc na wpółmartwe i specjalną funkcjonalnością nas nie zaskoczą.

Tags: ,
Author: Xion, posted under Applications » 2 comments

Przerywanie działania wątku

2008-05-12 21:17

Jednym z powodów używania wątków jest możliwość przerwania wykonywanych przezeń czynności właściwie w dowolnym momencie. Dzięki temu można na przykład wyposażyć aplikację okienkową w magiczny przycisk Anuluj obok paska postępu. Przez to zaś użytkownik ma wrażenie, że – nawet jeśli musi (dłuższą) chwilę zaczekać – nadal jest panem sytuacji :)
Jak można więc przerwać wątek, jeśli zachodzi taka potrzeba? Sposobów jest kilka:

  1. Najelegantszym jest sprawienie, aby zakończył się on “sam z siebie” i poczekanie na niego. Polega to na ustawieniu flagi sygnalizującej wątkowi konieczność zakończenia, którą oczywiście musi on regularnie sprawdzać. Stąd też główne pętle występujące w procedurach wątków są często w stylu while (!Terminating) { /* ... */ }. Dla porządku warto też (a w niektórych środowiskach trzeba), po ustawieniu rzeczonej flagi na wątek zaczekać. Czyni się to zwykle funkcją z join (‘złącz’) w nazwie: Thread.Join/join w .NET/Javie, pthread_join w POSIX-ie i… WaitForSingleObject w Windows API :)
  2. Jeśli wątek sporą część czasu poświęca na czekanie lub chociaż co jakiś czas przechodzi przynajmniej na krótko w stan uśpienia, wówczas można mu przerwać (interrupt). W .NET/Javie robi się to poprzez, niespodzianka, Thread.Interrupt/interrupt. Wówczas przy następnym wejściu do funkcji czekającej w rodzaju Thread.Sleep/sleep rzucany jest wyjątek (Thread)InterruptedException, który odwija stos wątku, kończąc w ten sposób jego działanie. W natywnych platformach nie może być oczywiście dokładnego odpowiednika podobnej operacji, lecz można ją symulować czekaniem na jakimś obiekcie synchronizacyjnym i sygnalizowaniem go, gdy chcemy to czekanie przerwać. W POSIX-ie funkcja pthread_cancel działa aczkolwiek w dość podobny sposób do Interrupt, pozwalając na posprzątanie zasobów w trakcie anulowania wątku.
  3. Najmniej eleganckim sposobem jest wreszcie brutalne przerwanie wątku, czyli próba jego natychmiastowego zakończenia w dowolnym momencie. Zarówno .NET, jak i Java rozwiązały to w podobny sposób: po wywoływaniu odpowiedniej metody (Thread.Abort/stop), w wątku rzucany jest bardzo specjalny wyjątek (ThreadAbortException lub ThreadDeath). Ma on tę cechę, że… przechodzi przez (prawie) wszystkie bloki catch – w .NET właściwie nie można go “zdusić”. To jednak sprawia, że taki wyjątek może wykonać po drodze wszystkie bloki finally, co pozwala zwolnić zawłaszczone zasoby i blokady oraz przywrócić obiekty synchronizujące do właściwego stanu. Występująca w Windows API funkcja TerminateThread takiej możliwości już nam nie daje, przez co jej użycie może prowadzić do różnych kłopotów.

Wnioski z tych trzech sposobów są mniej więcej takie, że pisząc kod wykonywany w osobnym wątku powinniśmy zawsze przewidzieć “czysty” sposób na jego zakończenie. Poleganie na przerywaniu lub brutalnym zakańczaniu wątków może się bowiem źle skończyć.

Tags: , ,
Author: Xion, posted under Programming » 2 comments

Potęga w 4 kilobajtach

2008-05-09 19:49
Screen z demka 4k autorstwa Charibo
Screen z demka 4k
autorstwa Charibo

Ostatnio na Warsztacie zapanował niecodzienny pęd do sceny – demosceny, rzecz jasna. Jego główną przyczyną, a może i skutkiem, jest oczywiście rozpoczynający się dzisiaj konkurs na najlepsze demo 4k. Pod tym tajemniczym skrótem kryje się maksymalny rozmiar takiego dema (co obejmuje plik wykonywalny i wszystkie wykorzystywane dane), który nie może przekroczyć granicy 4096 bajtów.
“A co można napisać na takim malutkim kawałeczku?”, pewnie chciałoby się spytać. Okazuje się, że całkiem sporo – pod warunkiem, że znamy kilka sztuczek oraz korzystamy z odpowiednich narzędzi. Jest to na przykład specjalny linker, który dokonuje wyjątkowo efektywnej kompresji wynikowego pliku. Oprócz należy też odpowiednio skonfigurować kompilator, włączając wszelkie optymalizacje rozmiaru generowanego kodu (kosztem jego szybkości) oraz pozbywając się niepotrzebnych dodatków.

Takich dodatkiem jest na przykład biblioteka czasu wykonania (runtime). Jej wykluczenie sprawia jednak, że tracimy kilka mechanizmów języka C++, jak chociażby część funkcji matematycznych. Do szczególnie dotkliwych może należeć na przykład brak operacji potęgowania w jakiejkolwiek formie – zarówno funkcji pow, jak i exp. Jeśli ich potrzebujemy, musimy sami je sobie zapewnić, co w przypadku niecałkowitego wykładnika może być kłopotliwe. Chyba że odwołamy się bezpośrednio do jednostki zmiennoprzecinkowej – na przykład tak:

  1. float pow(float a, float b)  // a^b
  2. {
  3.     __asm
  4.     {
  5.         fld1
  6.         fld a
  7.         fyl2x
  8.         fld b
  9.         fmulp ST(1), ST(0)    // na wierzchu b * log2(a)
  10.        
  11.         // obliczenie 2^(b * log2(a)), czyli a^b
  12.         fst ST(1)
  13.         frndint
  14.         fld1
  15.         fscale
  16.         fxch ST(1)
  17.         fsubr ST(0), ST(2)
  18.         f2xm1
  19.         fld1
  20.         faddp ST(1), ST(0)
  21.         fmulp ST(1), ST(0)
  22.         fstp ST(1)
  23.     }
  24. }

Samodzielnie wyprodukowanie tego kawałka nie było aczkolwiek takie proste (głównie ze względu na kłopotliwe wymagania co do argumentu instrukcji F2XM1, która dokonuje potęgowania). Dlatego prezentuję go tu dla potomności i pożytku wszystkich tworzących małe dema, licząc, że komuś może się przydać :)

Tags: , , , ,
Author: Xion, posted under Programming » 3 comments

Dynamicze tablice w C

2008-05-08 15:17

Czasem życie zmusza do pisania w sławetnym i na szczęście zanikającym już języku C. A tam nie ma chociażby takich luksusów jak STL z niezastąpionymi pojemnikami. O wszelkie struktury danych trzeba zatroszczyć się samemu, co obejmuje także tak podstawowe jak dynamiczne tablice.
Jak wiadomo, takie tablice należy samodzielnie alokować, zmieniać ich rozmiar (z kopiowaniem zawartości) oraz zwalniać, gdy nie są już potrzebne. Najwyraźniej więc wybitnie przydatne są tu funkcje malloc i free, prawda? Otóż nieprawda :)

O wiele wygodniej jest bowiem używać funkcji realloc:

  1. tab = (int*)realloc(tab, tab_size * sizeof(int));

Jej nazwa wskazuje, że jej głównym przeznaczeniem jest zmiana rozmiaru już zaalokowanego kawałka pamięci. Zazwyczaj sprowadza się to zresztą do przydzielenia nowego, skopiowania tam zawartości starej porcji i zwolnienia jej. Jednakże w dwóch szczególnych przypadkach realloc zachowuje się inaczej – zależy to od parametrów, jakie jej podamy:

  • jeżeli pierwszym parametrem będzie wskaźnik pusty (NULL), funkcja przydzieli pamięć w ilości bajtów wyrażonej drugim parametrem – czyli zachowa się jak malloc
  • jeśli zaś drugim parametrem będzie zero, to funkcja spróbuje zwolnić kawałek pamięci, na który pokazuje wskaźnik będący pierwszym parametrem – czyli zachowa się jak free

To sprawia, że możemy używać funkcji realloc w postaci wywołania podobnego jak powyżej zawsze wtedy, gdy musimy zmienić rozmiar tablicy. Można na przykład dodać do niej element w taki oto sposób:

  1. int* AddInt(int* tab, size_t* tab_size, int elem)
  2. {
  3.     int* new_tab = (int*)realloc(tab, (*tab_size + 1) *sizeof(int));
  4.     new_tab[(*tab_size)++] = elem;
  5.     return new_tab;
  6. }

Nie musimy się martwić, czy tablica została wcześniej zaalokowana czy nie. Analogicznie wygląda usuwanie elementów z końca lub początku tablicy – wówczas nie trzeba przejmować się tym, czy z tablicy coś zostanie. Tak naprawdę opakowywanie obu tych operacji w funkcje nie jest nawet specjalnie potrzebne.

Jedynym warunkiem, aby to wszystko działało, jest odpowiednie zainicjowanie wskaźnika na tablicę oraz zmiennej przechowującej jej rozmiar – co jest aczkolwiek dość oczywiste:

  1. int* tab = NULL;
  2. size_t tab_size = 0;

I to właściwie wszystko. W sumie więc nie jest to może std::vector, ale w C nie ma co wybrzydzać :)

Tags: ,
Author: Xion, posted under Programming » 2 comments

Vista i Eksplorator gier

2008-05-06 19:40

Oprócz wsparcia dla wielkiej i wspaniałej wersji 10 biblioteki DirectX, system Windows Vista ma przynajmniej jeszcze jeden feature związany z programowaniem gier (i przy okazji z graniem w nie). Nie jest on aczkolwiek aż tak szeroko znany, chociaż wszystkie niezbędne narzędzia potrzebne do korzystania z niego są zawarte – nomen omen – w DirectX SDK.

Eksplorator gier w Windows Vista
Eksplorator gier z zaznaczoną
najciekawszą pozycją ;-)

To Eksplorator gier – małe, dosyć niepozorne, ale w gruncie rzeczy całkiem potężne narzędzie – w tym sensie, że potrafi ono czasami… zablokować dostęp do niektórych plików na dysku :) To aczkolwiek robota kontroli rodzicielskiej, czyli funkcji bardzo ściśle z wspomnianym Eksploratorem związanej. Ale po kolei.
Eksplorator gier (dostępny przez Start > Gry) to program, za pomocą którego możemy przeglądać gry zainstalowane na naszym komputerze. Prezentuje on nam ich nazwy, loga, gatunki, wymagania sprzętowe (w postaci Indeksu wydajności Windows), klasyfikację treści (wymagany wiek, zawartość przemocy, wulgaryzmów, itp.) i oczywiście pozwala także rzeczone gry uruchamiać – o ile nie zabrania tego ewentualna kontrola rodzicielska. Niby proste, chociaż na pierwszy rzut oka można by przypuszczać, że aplikacja ta dysponuje jakąś sztuczną inteligencją lub zdolnościami paranormalnymi. No bo skąd właściwie bierze ona te wszystkie informacje?…

Edytor plików GDF
Edytor plików GDF
zawarty w DXSDK

Prawda jest naturalnie taka, że wszystkie te dane muszą być podane przez twórców gier. W tym celu należy stworzyć tzw. Game Definition File (GDF), który jest plikiem XML opisującym różne parametry gry. Do niego możemy też dołączyć kilka grafik, a następnie całość należy zlinkować jako zasoby (resources) do jakiegoś pliku wykonywalnego – .exe lub .dll. Część tych czynności jest wspomagana przez Game Definition File Editor – niewielkie narzędzie dostarczane wraz z DirectX SDK począwszy od zeszłego roku. Potrafi ono mianowicie wyprodukować skrypt zasobów (plik .rc), który możemy dołączyć np. do projektu w Visual C++, skompilować do .res i z linkować z naszą grą.

Taphoo w Eksploratorze gier
Klasyfikacji treści wymaga
niestety (albo raczej stety)
cyfrowego podpisania gry

Lecz niestety nie jest to koniec zabawy :) Cały ten system, dzięki któremu Eksplorator posiada informacje o zainstalowanych grach, działa częściowo w oparciu o COM, a sama gra wymaga rejestracji w systemie w dość specjalny sposób, zanim będzie ona widoczna w programie. Ten sposób spokojnie można nazwać “ręcznym”, bo obejmuje on:

  1. Stworzenie instancji interfejsu COM IGameExplorer.
  2. Wywołanie jego metody VerifyAccess z podaniem pliku GDF.
  3. Wywołanie metody AddGame z kilkoma parametrami, m.in. wspomnianym plikiem i ścieżką do katalogu instalacyjnego gry.
  4. Stworzeniu przynajmniej jednego skrótu (w ściśle określonym miejscu), który pozwoli np. uruchomić grę przy pomocy Eksploratora.

Urocze, prawda? ;-) Żeby było śmieszniej, wszystkie te czynności powinny być wykonane w trakcie instalacji gry (a dokładniej: na sam jej koniec), co wymaga intensywnej grzebaniny w używanym programie instalacyjnym (w celu wywołania funkcji z pomocniczej biblioteki DLL) lub po prostu napisania małego programiku, który zostanie odpalony na końcu setupu i wszystkim się zajmie. O ile mi wiadomo, ani InstallShield, ani Windows Installer, ani freeware’owy Inno Setup nie wspierają natywnie procesu rejestracji gier w podobny sposób jak chociażby instalacji czcionek w systemie.

“A więc po co to wszystko?”, można zapytać. Ano chociażby po to, żeby nasza cudna produkcja jakoś się wyróżniała :] Obecnie gry retailowe w większości rejestrują się Eksploratorze, lecz z pewnością czyni tak mniejszość gier typu casual czy share/freeware. Możemy więc choć trochę zabłysnąć w oczach przyszłego użytkownika (chociaż zasadniczo zalecam świecenie innymi zaletami).
Na koniec – jeśli zdecydujemy pobawić się całym tym mechanizmem – warto pamiętać o tym, że Eksplorator gier to rzecz istniejąca jedynie na Viście, więc tylko na tym systemie powinniśmy przeprowadzać proces rejestracji.

Troska o baterię laptopa

2008-05-04 13:35

Chociaż współcześnie gadżety są coraz mniejsze i coraz zmyślniejsze, to jednym z ich słabszych punktów jest zawsze zasilanie. Jest tak zapewne dlatego, że baterie działają w oparciu przede wszystkim o reakcje chemiczne. A ponieważ jak dotąd nie zanosi się, aby w najbliższej przyszłości upowszechniło się zasilanie bezprzewodowe, warto wiedzieć, jak właściwie postępować z bateriami, by zapewnić ich maksymalną możliwą wydajność. Jest ona szczególnie ważna w przypadku laptopów i palmtopów, które zużywają największe ilości energii.

Duży akumulator litowo-jonowy
Co za szczęście, że laptopy
nie potrzebują aż takich
dużych baterii :)

Obecnie najpopularniejsze są baterie litowo-jonowe (Li-Ion), głównie ze względu na stosunek ceny do jakości i wygody użytkowania. Przy korzystaniu z takich baterii warto pamiętać o takich oto prostych regułach:

  • W przeciwieństwie np. do starszych baterii niklowo-wodorkowych (Ni-MH), akumulatory Li-Ion nie wymagają tzw. formowania, czyli kilkukrotnego ładowania i rozładowania na początku użytkowania. Tak naprawdę baterie litowe nigdy nie powinny być całkowicie rozładowywane, gdyż szkodzi to ich pojemności i żywotności. Dlatego właśnie systemy operacyjne zwykle wykrywają stan baterii laptopów i “w ostatniej chwili” przełączają się w stan hibernacji.
  • Zupełnie odwrotnie niż akumulatory Ni-MH, baterie Li-Ion powinny być doładowywane kiedy tylko to możliwe. Znów jest to bardzo praktyczne zwłaszcza w przypadku komputerów przenośnych, które często są podłączane do prądu.
  • Tym, co skraca żywotność baterii jonowych, jest przede wszystkim temperatura. Jeśli jest ona zbyt wysoka przez dłuższy czas – co, niestety, jest powszechne w przypadku laptopów, które generalnie mają problemy z chłodzeniem podzespołów – pojemność baterii ulega zmniejszeniu. Dlatego też w przypadku dłuższej pracy na zasilaniu sieciowym, dobrze jest wyjąć z komputera baterię, by się nie nagrzewała.

W ten sposób możemy przedłużyć życie baterii Li-Ion, ale trzeba pamiętać, że i tak nie jest on zbyt duży i wynosi mniej więcej 3 lata. Co więcej, jest on zdeterminowany w chwili produkcji i właściwie tylko od szczęścia zależy, czy trafi się nam model krótko- czy (względnie) długożyjący.

Najwyraźniej więc – mimo coraz dalej postępującej bezprzewodowości – kable zasilające będą nam ciągle towarzyszyć jeszcze przez całkiem długi czas…

Tags: , ,
Author: Xion, posted under Computer Science & IT » 6 comments
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.