GNU/Linux >> Belajar Linux >  >> Linux

Pilih Linux () vs ppoll () vs pselect ()

Antara (p)pilih dan (p)poll adalah perbedaan yang agak halus:

Untuk pilih, Anda harus menginisialisasi dan mengisi bitmap fd_set yang jelek setiap kali sebelum Anda memanggil pilih karena pilih memodifikasinya di tempat dengan cara "destruktif". (jajak pendapat membedakan antara .events dan .revents anggota di struct pollfd ).

Setelah memilih, seluruh bitmap sering dipindai (oleh orang/kode) untuk acara meskipun sebagian besar fds bahkan tidak ditonton.

Ketiga, bitmap hanya dapat menangani fds yang jumlahnya kurang dari batas tertentu (implementasi kontemporer:antara 1024..4096), yang mengesampingkannya dalam program di mana fds tinggi dapat dicapai dengan mudah (walaupun program semacam itu cenderung sudah menggunakan epoll sebagai gantinya).


Saya sarankan dengan memulai perbandingan dengan select() vs poll() . Linux juga menyediakan pselect() dan ppoll(); dan const sigset_t * ekstra argumen ke pselect() dan ppoll() (vs select() dan poll() ) memiliki efek yang sama pada setiap "varian-p", seolah-olah. Jika Anda tidak menggunakan sinyal, Anda tidak memiliki ras untuk dilindungi, jadi pertanyaan dasarnya adalah tentang efisiensi dan kemudahan pemrograman.

Sementara itu sudah ada jawaban stackoverflow.com di sini:apa perbedaan polling dan pilih.

Sedangkan untuk balapan:setelah Anda mulai menggunakan sinyal (untuk alasan apa pun), Anda akan mengetahui bahwa secara umum, penangan sinyal sebaiknya menyetel variabel bertipe volatile sig_atomic_t untuk menunjukkan bahwa sinyal telah terdeteksi. Alasan mendasar untuk ini adalah banyak panggilan perpustakaan tidak masuk kembali, dan sinyal dapat dikirim saat Anda "di tengah" rutinitas seperti itu. Misalnya, cukup mencetak pesan ke struktur data bergaya aliran seperti stdout (C) atau cout (C++) dapat menyebabkan masalah masuk kembali.

Misalkan Anda memiliki kode yang menggunakan volatile sig_atomic_t flag variabel, mungkin untuk menangkap SIGINT , kira-kira seperti ini (lihat juga http://pubs.opengroup.org/onlinepubs/007904975/functions/sigaction.html):

volatile sig_atomic_t got_interrupted = 0;
void caught_signal(int unused) {
    got_interrupted = 1;
}
...
    struct sigaction sa;
    sa.sa_handler = caught_signal;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGINT, &sa, NULL) == -1) ... handle error ...
    ...

Sekarang, di bagian utama kode Anda, Anda mungkin ingin "berjalan sampai terputus":

    while (!got_interrupted) {
         ... do some work ...
    }

Ini baik-baik saja sampai Anda mulai perlu melakukan panggilan yang menunggu beberapa masukan/keluaran, seperti select atau poll . Tindakan "menunggu" perlu menunggu I/O tersebut—tetapi juga perlu menunggu SIGINT mengganggu. Jika Anda hanya menulis:

    while (!got_interrupted) {
        ... do some work ...
        result = select(...); /* or result = poll(...) */
    }

maka kemungkinan interupsi akan terjadi tepat sebelum Anda memanggil select() atau poll() , daripada sesudahnya. Dalam hal ini, Anda mengalami gangguan—dan variabel got_interrupted diatur — tetapi setelah itu, Anda mulai menunggu. Anda seharusnya memeriksa got_interrupted variabel sebelum Anda mulai menunggu, bukan setelahnya.

Anda dapat mencoba menulis:

    while (!got_interrupted) {
        ... do some work ...
        if (!got_interrupted)
            result = select(...); /* or result = poll(...) */
    }

Ini mengecilkan "jendela balapan", karena sekarang Anda akan mendeteksi interupsi jika itu terjadi saat Anda berada di kode "lakukan beberapa pekerjaan"; tetapi masih ada perlombaan, karena interupsi dapat terjadi tepat setelah Anda menguji variabel, tetapi sebelumnya pilih-atau-jajak pendapat.

Solusinya adalah membuat urutan "uji, lalu tunggu" "atomik", menggunakan properti pemblokiran sinyal dari sigprocmask (atau, dalam kode utas POSIX, pthread_sigmask ):

sigset_t mask, omask;
...
while (!got_interrupted) {
    ... do some work ...
    /* begin critical section, test got_interrupted atomically */
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    if (sigprocmask(SIG_BLOCK, &mask, &omask))
        ... handle error ...
    if (got_interrupted) {
        sigprocmask(SIG_SETMASK, &omask, NULL); /* restore old signal mask */
        break;
    }
    result = pselect(..., &omask); /* or ppoll() etc */
    sigprocmask(SIG_SETMASK, &omask, NULL);
    /* end critical section */
}

(kode di atas sebenarnya tidak terlalu bagus, ini disusun untuk ilustrasi daripada efisiensi -- lebih efisien untuk melakukan manipulasi topeng sinyal sedikit berbeda, dan menempatkan pengujian "terganggu" secara berbeda).

Sampai Anda benar-benar mulai perlu menangkap SIGINT , namun, Anda hanya perlu membandingkan select() dan poll() (dan jika Anda mulai membutuhkan deskriptor dalam jumlah besar, beberapa hal berbasis peristiwa seperti epoll() lebih efisien daripada keduanya).


Linux
  1. Tidak Dapat Mengakses Situs Https Terpilih Di Linux Melalui Pppoe?

  2. Perintah mv Linux

  3. Linux du perintah

  1. Perintah ip Linux

  2. Perintah cd Linux

  3. Pilih teks menggunakan keyboard di shell linux

  1. Cara menginstal Erlang di Rocky Linux/Alma Linux/CentOS 8

  2. Linux – Apakah Kernel Linux/unix yang Berbeda Dapat Dipertukarkan?

  3. Perangkat Android Emulator mogok saat memulai di Android Studio (Linux)