GNU/Linux >> Belajar Linux >  >> Linux

Buat pengatur waktu di Linux

Waktu peristiwa tertentu adalah tugas umum untuk pengembang. Skenario umum untuk pengatur waktu adalah pengawas, eksekusi tugas secara siklik, atau penjadwalan acara untuk waktu tertentu. Dalam artikel ini, saya menunjukkan cara membuat timer interval yang sesuai dengan POSIX menggunakan timer_create(...).

Anda dapat mengunduh kode sumber untuk contoh berikut dari GitHub.

Siapkan Qt Creator

Saya menggunakan Qt Creator sebagai IDE untuk contoh ini. Untuk menjalankan dan men-debug kode contoh di Qt Creator, kloning repositori GitHub, buka Qt Creator, dan buka File -> Open File or Project... dan pilih CMakeLists.txt :

Setelah memilih rantai alat, klik Konfigurasikan Proyek . Proyek ini berisi tiga contoh independen (kami hanya akan membahas dua di antaranya dalam artikel ini). Dengan menu bertanda hijau, beralih di antara konfigurasi untuk setiap contoh dan aktifkan Jalankan di terminal untuk masing-masing (lihat tanda kuning di bawah). Contoh yang saat ini aktif untuk membangun dan men-debug dapat dipilih melalui Debug tombol di pojok kiri bawah (lihat tanda oranye di bawah):

Pengatur waktu utas

Mari kita lihat simple_threading_timer.c contoh. Ini adalah yang paling sederhana:Ini menunjukkan bagaimana penghitung waktu interval dibuat, yang memanggil fungsi kedaluwarsa pada kadaluarsa. Pada setiap kedaluwarsa, utas baru dibuat di mana fungsi kedaluwarsa disebut.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

void expired(union sigval timer_data);

pid_t gettid(void);

struct t_eventData{
    int myData;
};

int main()
{
    int res = 0;
    timer_t timerId = 0;

    struct t_eventData eventData = { .myData = 0 };


    /*  sigevent specifies behaviour on expiration  */
    struct sigevent sev = { 0 };

    /* specify start delay and interval
     * it_value and it_interval must not be zero */

    struct itimerspec its = {   .it_value.tv_sec  = 1,
                                .it_value.tv_nsec = 0,
                                .it_interval.tv_sec  = 1,
                                .it_interval.tv_nsec = 0
                            };

    printf("Simple Threading Timer - thread-id: %d\n", gettid());

    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = &expired;
    sev.sigev_value.sival_ptr = &eventData;


    /* create timer */
    res = timer_create(CLOCK_REALTIME, &sev, &timerId);


    if (res != 0){
        fprintf(stderr, "Error timer_create: %s\n", strerror(errno));
        exit(-1);
    }

    /* start timer */
    res = timer_settime(timerId, 0, &its, NULL);

    if (res != 0){
        fprintf(stderr, "Error timer_settime: %s\n", strerror(errno));
        exit(-1);
    }

    printf("Press ETNER Key to Exit\n");
    while(getchar()!='\n'){}
    return 0;
}


void expired(union sigval timer_data){
    struct t_eventData *data = timer_data.sival_ptr;
    printf("Timer fired %d - thread-id: %d\n", ++data->myData, gettid());
}

Keuntungan dari pendekatan ini adalah jejaknya yang kecil, dalam hal kode dan debugging sederhana. Kerugiannya adalah overhead tambahan karena pembuatan utas baru saat kedaluwarsa dan, akibatnya, perilaku yang kurang deterministik.

Lebih banyak sumber daya Linux

  • Lembar contekan perintah Linux
  • Lembar contekan perintah Linux tingkat lanjut
  • Kursus online gratis:Ikhtisar Teknis RHEL
  • Lembar contekan jaringan Linux
  • Lembar contekan SELinux
  • Lembar contekan perintah umum Linux
  • Apa itu container Linux?
  • Artikel Linux terbaru kami

Pengatur Waktu Sinyal Interupsi

Kemungkinan lain untuk diberi tahu oleh timer yang kedaluwarsa didasarkan pada sinyal kernel. Alih-alih membuat thread baru setiap kali timer berakhir, kernel mengirimkan sinyal ke proses, proses diinterupsi, dan penangan sinyal yang sesuai dipanggil.

Karena tindakan default saat menerima sinyal adalah untuk menghentikan proses (lihat halaman manual sinyal), kita harus mempersiapkan Qt Creator terlebih dahulu sehingga proses debug dapat dilakukan dengan benar.

Perilaku default Qt Creator saat debuggee menerima sinyal adalah:

  • Interupsi eksekusi dan alihkan ke konteks debugger.
  • Menampilkan jendela pop-up yang memberi tahu pengguna tentang penerimaan sinyal.

Kedua tindakan tersebut tidak diinginkan karena penerimaan sinyal adalah bagian dari aplikasi kita.

Qt Creator menggunakan GDB di latar belakang. Untuk mencegah GDB menghentikan eksekusi saat proses menerima sinyal, buka Alat -> Opsi , pilih Debugger , dan navigasikan ke Lokal &Ekspresi . Tambahkan ekspresi berikut ke Penyesuaian Helper Debugging :

handle SIG34 nostop pass

Anda dapat menemukan informasi lebih lanjut tentang penanganan sinyal GDB di dokumentasi GDB.

Selanjutnya, kita ingin menekan jendela pop-up yang memberi tahu kita setiap kali sinyal diterima saat kita berhenti di pengendali sinyal:

Untuk melakukannya, navigasikan ke tab GDB dan hapus centang pada kotak yang ditandai:

Sekarang Anda dapat men-debug signal_interrupt_timer . dengan benar . Implementasi aktual dari pengatur waktu sinyal sedikit lebih rumit:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#define UNUSED(x) (void)(x)

static void handler(int sig, siginfo_t *si, void *uc);
pid_t gettid(void);

struct t_eventData{
    int myData;
};

int main()
{
    int res = 0;
    timer_t timerId = 0;


    struct sigevent sev = { 0 };
    struct t_eventData eventData = { .myData = 0 };

    /* specifies the action when receiving a signal */
    struct sigaction sa = { 0 };

    /* specify start delay and interval */
    struct itimerspec its = {   .it_value.tv_sec  = 1,
                                .it_value.tv_nsec = 0,
                                .it_interval.tv_sec  = 1,
                                .it_interval.tv_nsec = 0
                            };

    printf("Signal Interrupt Timer - thread-id: %d\n", gettid());

    sev.sigev_notify = SIGEV_SIGNAL; // Linux-specific
    sev.sigev_signo = SIGRTMIN;
    sev.sigev_value.sival_ptr = &eventData;

    /* create timer */
    res = timer_create(CLOCK_REALTIME, &sev, &timerId);

    if ( res != 0){
        fprintf(stderr, "Error timer_create: %s\n", strerror(errno));
        exit(-1);
    }

    /* specifz signal and handler */
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = handler;

    /* Initialize signal */
    sigemptyset(&sa.sa_mask);

    printf("Establishing handler for signal %d\n", SIGRTMIN);

    /* Register signal handler */
    if (sigaction(SIGRTMIN, &sa, NULL) == -1){
        fprintf(stderr, "Error sigaction: %s\n", strerror(errno));
        exit(-1);
    }

    /* start timer */
    res = timer_settime(timerId, 0, &its, NULL);

    if ( res != 0){
        fprintf(stderr, "Error timer_settime: %s\n", strerror(errno));
        exit(-1);
    }

    printf("Press ENTER to Exit\n");
    while(getchar()!='\n'){}
    return 0;
}



static void
handler(int sig, siginfo_t *si, void *uc)
{
    UNUSED(sig);
    UNUSED(uc);
    struct t_eventData *data = (struct t_eventData *) si->_sifields._rt.si_sigval.sival_ptr;
    printf("Timer fired %d - thread-id: %d\n", ++data->myData, gettid());
}

Berbeda dengan timer threading, kita harus menginisialisasi sinyal dan mendaftarkan penangan sinyal. Pendekatan ini lebih berkinerja karena tidak akan menyebabkan pembuatan utas tambahan. Untuk alasan ini, eksekusi penangan sinyal juga lebih deterministik. Kekurangannya jelas merupakan upaya konfigurasi ekstra untuk men-debug ini dengan benar.

Ringkasan

Kedua metode yang dijelaskan dalam artikel ini adalah implementasi timer yang dekat dengan kernel. Bahkan jika fungsi timer_create(...) adalah bagian dari spesifikasi POSIX, tidak mungkin untuk mengkompilasi kode sampel pada sistem FreeBSD karena perbedaan kecil dalam struktur data. Selain kelemahan ini, implementasi semacam itu memberi Anda kontrol yang sangat baik untuk aplikasi pengaturan waktu tujuan umum.


Linux
  1. Cara membuat paket RPM Linux

  2. Cara Membuat Swap di Linux

  3. Linux ln perintah

  1. Buat brankas file terenkripsi di Linux

  2. Cara Membuat Script Perintah Linux

  3. Cara membuat layanan Systemd di Linux

  1. Cara membuat file swap di Linux

  2. Buat file swap Linux

  3. Ubah timer kernel linux