Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Poprzednia wersja Nowa wersja | Poprzednia wersja | ||
sk2:sockets_concurrency [2022/11/07 21:13] jkonczak [poll] |
sk2:sockets_concurrency [2023/11/09 12:30] (aktualna) jkonczak [Funkcje biblioteczne] |
||
---|---|---|---|
Linia 22: | Linia 22: | ||
System Linux zawiera 3 podstawowe funkcje pozwalające na czekanie na przychodzące zdarzenia na deskryptorach plików: | System Linux zawiera 3 podstawowe funkcje pozwalające na czekanie na przychodzące zdarzenia na deskryptorach plików: | ||
* ''select'' – "klasyczna" funkcja, ma kilka dziwnych ograniczeń. Dostaje zbiór deskryptorów, oczekuje na zdarzenie, modyfikuje przekazany zbiór deskryptorów zostawiając tylko te na których można wykonać read/write/lub na których wystąpił wyjątek. (POSIX) | * ''select'' – "klasyczna" funkcja, ma kilka dziwnych ograniczeń. Dostaje zbiór deskryptorów, oczekuje na zdarzenie, modyfikuje przekazany zbiór deskryptorów zostawiając tylko te na których można wykonać read/write/lub na których wystąpił wyjątek. (POSIX) | ||
- | * ''poll'' – zbudowana podobnie jak ''select'', ale m.inn. nie ma ograniczenia na ilość monitorowanych deskryptorów, można użyć ponownie struktury opisującej deskryptory etc. (POSIX) | + | * ''poll'' – zbudowana podobnie jak ''select'', ale m.inn. nie ma ograniczenia na numery monitorowanych deskryptorów((Patrz [[https://man7.org/linux/man-pages/man2/select.2.html|man 2 select]].)), można użyć ponownie struktury opisującej deskryptory etc. (POSIX) |
* ''epoll'' – specyficzna dla Linuksa funkcja. Inny pomysł: program informuje jądro systemu na które deskryptory chce czekać, potem wywołuje funkcję czekającą na zdarzenie i dostaje deskryptory które są gotowe do pracy. | * ''epoll'' – specyficzna dla Linuksa funkcja. Inny pomysł: program informuje jądro systemu na które deskryptory chce czekać, potem wywołuje funkcję czekającą na zdarzenie i dostaje deskryptory które są gotowe do pracy. | ||
Dłuższe porównanie: http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/ | Dłuższe porównanie: http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/ | ||
+ | <small>Od kilku lat trwają prace nad mechanizmem ''[[https://en.wikipedia.org/wiki/Io_uring|io_uring]]'', pozwalającym na wykonywanie jednocześnie wielu operacji na plikach. Mechanizm pozwala na przekazanie do kernela żądań wykonania konkretnych operacji, oraz oferuje funkcję do czekania na wykonanie jakiejś ze zleconych wcześniej operacji.</small> | ||
===== poll ===== | ===== poll ===== | ||
Linia 43: | Linia 44: | ||
<code cpp> | <code cpp> | ||
pollfd σληζονε[ιλε]; ─┐ | pollfd σληζονε[ιλε]; ─┐ | ||
- | σληζονε[0].fd = σοκ_α; │ | + | σληζονε[0].fd = σοκητ_α; │ |
σληζονε[0].events = POLLIN; ├─ (2) | σληζονε[0].events = POLLIN; ├─ (2) | ||
- | σληζονε[1].fd = σοκ_β; │ | + | σληζονε[1].fd = σοκητ_β; │ |
σληζονε[1].events = POLLIN; ─┘ | σληζονε[1].events = POLLIN; ─┘ | ||
... | ... | ||
Linia 53: | Linia 54: | ||
if(σληζονε[0].revents & POLLIN){ ─┐ | if(σληζονε[0].revents & POLLIN){ ─┐ | ||
- | read(σοκ_α, ... │ | + | read(σοκητ_α, ... │ |
... │ | ... │ | ||
} ├─ (4) | } ├─ (4) | ||
if(σληζονε[1].revents & POLLIN){ │ | if(σληζονε[1].revents & POLLIN){ │ | ||
- | read(σοκ_β, ... │ | + | read(σοκητ_β, ... │ |
... ─┘ | ... ─┘ | ||
} | } | ||
Linia 75: | Linia 76: | ||
<code cpp> | <code cpp> | ||
- | int sock = socket(... | + | int εΦδ = epoll_create1(0); ═╾─ (1) |
- | ... | + | |
+ | epoll_event ωπις; ─┐ | ||
+ | ωπις.events = EPOLLIN; │ | ||
+ | ωπις.data.u64 = 987654321; │ | ||
+ | epoll_ctl(εΦδ, EPOLL_CTL_ADD, σοκητ_α, &ωπις); ├─ (2) | ||
+ | ωπις.data.u64 = 123456789; │ | ||
+ | epoll_ctl(εΦδ, EPOLL_CTL_ADD, σοκητ_β, &ωπις); │ | ||
+ | ... ─┘ | ||
+ | // Poza .u64 w unii są też .fd i .ptr | ||
+ | |||
+ | while(true) { | ||
+ | int γωτουε = epoll_wait(εΦδ, &ωπις, 1, -1); ═╾─ (3) | ||
+ | |||
+ | if(ωπις.events & EPOLLIN && ─┐ | ||
+ | ωπις.data.u64 == 987654321 ){ │ | ||
+ | read(σοκητ_α, ... │ | ||
+ | } ├─ (4) | ||
+ | if(ωπις.events & EPOLLIN && │ | ||
+ | ωπις.data.u64 == 123456789 ){ │ | ||
+ | read(σοκητ_β, ... ─┘ | ||
+ | } | ||
+ | ... | ||
+ | } | ||
+ | </code> | ||
- | int fd = epoll_create1(0); // (1) | + | ++++Przykład użycia pola ''.data.ptr''| |
+ | <code cpp> | ||
+ | struct Handler { | ||
+ | virtual void handleEvent(uint32_t event) = 0; | ||
+ | }; | ||
- | epoll_event event; // \. | + | struct Client : public Handler { |
- | event.events = EPOLLIN; // | | + | Client(int fd); |
- | event.data.fd = sock; // > (2) | + | int fd; |
- | //event.data.u64 = 0xdeadbeef // | | + | virtual void handleEvent(uint32_t event) override { |
- | //event.data.ptr = funkcja; // / | + | if(event & EPOLLIN){ |
+ | read(fd, ... | ||
+ | } | ||
+ | ... | ||
+ | } | ||
+ | ... | ||
+ | }; | ||
- | epoll_ctl(fd, EPOLL_CTL_ADD, sock, &event); // \. | + | std::list<Client> clients; |
- | ... // > (2) | + | int epollfd; |
- | epoll_ctl(fd, EPOLL_CTL_ADD, othersock, &event); // / | + | |
- | + | void newClientArrived(){ | |
- | int resultCount = epoll_wait(fd, &event, 1, -1); // (3) | + | int sock = accept(... |
- | + | clients.emplace_back(sock); | |
- | if( event.events & EPOLLIN && event.data.fd == sock ){ // \. | + | epoll_event ee {EPOLLIN, {.ptr=&clients.back()}}; // referencje do elementów listy są ważne |
- | read(sock, ... // > (4) | + | epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &ee); // do usunięcia wskazywanego elementu |
- | ... // / | + | ... |
+ | } | ||
+ | |||
+ | int main(){ | ||
+ | ... | ||
+ | epoll_event ee; | ||
+ | while(epoll_wait(epollfd, &ee, 1, -1)) | ||
+ | ((Handler*)ee.data.ptr)->handleEvent(ee.events); | ||
} | } | ||
</code> | </code> | ||
- | <html><small></html>Przykład użycia pola ''.data.ptr'' | + | ++++ |
- | <code cpp> | + | |
- | std::function<void()> readFromSock = ... // np. 'mySockObject;' czy 'std::bind(myReadFunc, sock);' | + | |
- | epoll_event ee {}; | + | |
- | ee.events = EPOLLIN; | + | |
- | ee.data.ptr = &readFromSock; | + | |
- | epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &ee); | + | |
- | ... | + | |
- | while(epoll_wait(epollfd, &ee, 1, -1)) | + | |
- | (*(std::function<void()>*)ee.data.ptr)(); | + | |
- | </code> | + | |
- | <html></small></html> | + | |
//Zadanie 4.// Powtórz Zadanie 1, ale tym razem jako jednowątkowy program wykorzystujący mechanizm epoll. | //Zadanie 4.// Powtórz Zadanie 1, ale tym razem jako jednowątkowy program wykorzystujący mechanizm epoll. | ||
//Zadanie 5.// Napisz jednowątkowy serwer czatu używając ''poll'' lub ''epoll_wait''. | //Zadanie 5.// Napisz jednowątkowy serwer czatu używając ''poll'' lub ''epoll_wait''. |