Narzędzia użytkownika

Narzędzia witryny


sk2:sockets_concurrency

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
sk2:sockets_concurrency [2021/12/06 21:24]
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 35: Linia 36:
     * ''​.events''​ – zbiór monitorowanych zdarzeń:     * ''​.events''​ – zbiór monitorowanych zdarzeń:
       *  ''​POLLIN''​ – funkcja ''​poll''​ ma się przerwać, jeśli można wywołać bez czekania ''​read()/​…''​ lub ''​acccept()''​       *  ''​POLLIN''​ – funkcja ''​poll''​ ma się przerwać, jeśli można wywołać bez czekania ''​read()/​…''​ lub ''​acccept()''​
-      *  ''​POLLOUT''​ – funkcja ''​poll''​ ma się przerwać, jeśli można wywołać bez czekania ''​write()/​…''​ \\ <​html><​small></​html>​Uwaga: jeśli spróbujesz zapisać więcej bajtów niż jest miejsca w buforze nadawczym, ''​write''​ i tak się zablokuje<​html></​small></​div></​li></​ul><​div class="​li"></​html>​ reszta zdarzeń (''​POLLHUP'',​ ''​POLLERR'',​ ''​POLLPRI'',​ …) opisana w ''​man poll''​ <​html></​div><​!--</​html>​+      *  ''​POLLOUT''​ – funkcja ''​poll''​ ma się przerwać, jeśli można wywołać bez czekania ''​write()/​…''​ \\ Uwaga: na możliwość wysłania danych czeka się wtedy kiedy ma się dane do wysłania \\ Uwaga: jeśli spróbujesz zapisać więcej bajtów niż jest miejsca w buforze nadawczym, ''​write''​ i tak się zablokuje<​html></​div></​li></​ul><​div class="​li"></​html>​ reszta zdarzeń (''​POLLHUP'',​ ''​POLLERR'',​ ''​POLLPRI'',​ …) opisana w ''​man poll''​ <​html></​div><​!--</​html>​
     * <​html>​--><​div class="​li"></​html>​     * <​html>​--><​div class="​li"></​html>​
     * zostawić w spokoju ''​.revents''​ – tam pojawi się informacja o tym co wystąpiło     * zostawić w spokoju ''​.revents''​ – tam pojawi się informacja o tym co wystąpiło
Linia 42: Linia 43:
  
 <code cpp> <code cpp>
-pollfd ​nacoczekac[5]{}                 // \. +pollfd ​σληζονε[ιλε];                       ─┐ 
-nacoczekac[0].fd=sock1                 // ​ > (2) +σληζονε[0].fd = σοκητ_α                   │ 
-nacoczekac[0].events=POLLIN; ​            // /+σληζονε[0].events = POLLIN; ​                ​├─ ​(2) 
 +σληζονε[1].fd = σοκητ_β; ​                   │ 
 +σληζονε[1].events = POLLIN; ​               ​─┘
 ... ...
  
-int gotowe ​= poll(nacoczekac5, -1);    // ​(3)+while(true) { 
 +    ​int γωτουε ​= poll(σληζονειλε, -1);   ═╾─ ​(3)
  
-for(pollfd ​opis : nacoczekac) {        ​// \+    if(σληζονε[0].revents ​POLLIN){       ─┐ ​  
-    if(opis.revents & POLLIN) {          // ​ | +        read(σοκητ_α, ​...                   │ 
-        if(opis.fd == sock1) {           // ​ | +        ...                                 │ 
-            read(opis.fd, ...            // ​  > (4) +    }                                       ​├─ (4) 
-            ...                          // ​ | +    if(σληζονε[1].revents & POLLIN){ ​       ​ 
-    }}                                   // ​ | +        read(σοκητ_β, ...                   │ 
-                                       // /+        ...                                ​─┘ 
 +    } 
 +    ... 
 +}
 </​code>​ </​code>​
  
Linia 69: 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 eventoverride { 
-//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''​.
sk2/sockets_concurrency.1638822259.txt.gz · ostatnio zmienione: 2021/12/06 21:24 przez jkonczak