Chciałbym opublikować kawałek kodu, który napisałem pod wpływem emocji w ramach nauki na końcowe kolokwium z systemów operacyjnych. Zadania, które dostawaliśmy tam były niemożliwe do zrobienia bez dobrej znajomości API UNIXa dotyczącego komunikacji międzyprocesowej i przygotowania sobie jakiegoś kodu wcześniej. Teoretycznie można było korzystać z Internetu i dowolnych własnych zasobów, ale bez wstępnego przygotowania nie było szans ;). Większość znajomych przygotowywała więc sobie rozwiązania dotychczasowych zadań z laboratorium w nadziei, że będą się dały zaadaptować do kolokwium.
QED, bo tak nazywa się biblioteka, powstała jako wynik frustracji po słabym zaliczeniu pierwszego terminu. Opakowuje ona całe to przykre i bolesne w użyciu API IPC UNIX'a do postaci prostych klas i funkcji C++. Większość zadań da się zrobić bez ani jednej linii kodu w czystym UNIXowym API :).
Biblioteka QED oraz przykładowe zadania z laboratoriów / kolokwium.
Biblioteczka ta zawiera:
- Uproszczony
lexical_cast
- Obiekty do łatwego synchronizowania operacji na
std::ostream
(tak, na std::cout
też!) w programach wielowątkowych
- Funkcję do pobierania czasu z milisekundową rozdzielczością
- Pomocnicze makra zastępujące powtarzający się w kółko kod
- Pomocnicze funkcje do wygodnego
fork()
(łącznie z przepinaniem STDIN i STDOUT dziecka); fork-exec idiom trzeba sobie zrobić samemu, ale co to za problem wywołać sobie funkcję exec()
:P.
- Klasy izolujące nienazwane i nazwane pipe'y (FIFO), semafory, pamięć współdzieloną i kolejki komunikatów
- Inne pomocnicze funkcje
Mam szczerą nadzieję, że kod ten przyda się przynajmniej tym z Czytelników, którzy już za rok (albo i wcześniej) zmierzą się z Systemami Operacyjnymi na IS :).
Dlaczego taka nazwa? QED oznacza elektrodynamikę kwantową - bardzo pokręconą dziedzinę fizyki, o której czytałem sobie "do obiadu" w okresie prac nad powyższą biblioteką. Q.E.D. to też łaciński skrót oznaczający Quod erat demonstrandum ("Co było do udowodnienia") - co dobrze współgrało z moją frustracją po pierwszym terminie (na zasadzie: "no, na drugim pokażę!").
Dla niewystarczająco przekonanych, przykład kodu:
int process_beta(void* data)
{
betaQueue.attach();
alphaSharedQueue.attach();
char buffer[1024];
while(true)
{
std::memset(buffer, 0, 1024*sizeof(char));
betaQueue.receive_message(buffer);
buffer[std::max(static_cast<int>(std::strlen(buffer)) - 2, 0)] = '\0';
alphaSharedQueue.send_message(buffer);
}
return 0;
}
Oto kod procesu, który odbiera informacje z kolejki komunikatów, obcina im dwa ostatnie znaki i wysyła je inną kolejką komunikatów.
Teraz, wyobraź sobie, że piszesz w czystym UNIX API :P.