/ / Cơ chế hẹn giờ với C và Linux

Cơ chế hẹn giờ với C và Linux

Cơ chế hẹn giờ cho phép bạn lên lịch cho nhân hệ điều hành để thông báo cho ứng dụng khi thời gian định trước trôi qua. Thông thường, bạn sẽ sử dụng chúng bằng cách cung cấp hai phần thông tin. Trước tiên, bạn sẽ cần chỉ định thời gian bộ hẹn giờ sẽ mất trước khi thông báo. Thứ hai, bạn sẽ cần chuẩn bị một chức năng gọi lại để hoạt động khi thông báo đó xảy ra.

Phương pháp tiếp cận truyền thống đối với bộ hẹn giờ

Các cơ chế hẹn giờ trong các hệ thống dựa trên Linux và Unix đã phát triển để phục vụ các nhu cầu khác nhau. Các cách tiếp cận khác nhau có thể giúp bạn giải quyết các dạng vấn đề khác nhau. Tuy nhiên, bạn sẽ thường thấy phiên bản đầu tiên của báo thức() cơ chế vẫn đang được sử dụng.

Chức năng báo thức là cách đơn giản nhất để sử dụng bộ hẹn giờ; đây là nguyên mẫu của nó:

unsigned int alarm(unsigned int seconds);

Sử dụng phương pháp này, bạn chỉ có thể chỉ định thời gian tính bằng giây. Khi hết thời gian, hệ điều hành sẽ gửi SIGALRM tín hiệu cho ứng dụng của bạn. Để xử lý thời hạn của bộ hẹn giờ trong ứng dụng của bạn, bạn cũng nên xác định một hàm gọi lại.

Đây là một ví dụ về hàm xử lý tín hiệu:

LÀM VIDEO TRONG NGÀY
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>

void timer_callback(int signum)
{
time_t now = time(NULL);
printf("Signal %d caught on %li", signum, now);
}

int main()
{
signal(SIGALRM, timer_callback);
alarm(1);
sleep(3);
return 0;
}


Mã này tăng một SIGALRM tín hiệu sau 1 thứ hai. Nếu bạn muốn tăng thời gian trễ hẹn giờ lên năm giây, chỉ cần gọi báo động (5) thay vì. Để dừng bộ đếm thời gian, hãy chuyển giá trị 0: báo thức (0).

Khi hết thời gian, bộ hẹn giờ bạn sử dụng sẽ không khởi động lại theo định kỳ. Ví dụ: nếu bạn muốn trì hoãn thêm một giây nữa, bạn nên khởi động lại cơ chế bằng một cuộc gọi khác tới báo thức().

Mặc dù dễ sử dụng, phương pháp này có một số nhược điểm:

  • Chỉ một bộ hẹn giờ tại một thời điểm.
  • Không hỗ trợ hẹn giờ định kỳ.
  • Bạn chỉ có thể cung cấp khoảng thời gian theo bội số của giây nguyên.
  • Không có cách nào để biết thời gian còn lại trên một bộ đếm thời gian.

Lưu mã mẫu được cung cấp ở trên dưới dạng báo động.c. Khi bạn biên dịch và chạy nó, chương trình sẽ gọi timer_callback hoạt động sau một giây. Sau đó, nó sẽ đợi trong hai giây còn lại do ngủ (3) dòng, sau đó kết thúc.


$ gcc -o alarm alarm.c
$ time ./alarm
Signal 14 caught on 1653490465
real 0m1.004s
user 0m0.000s
sys 0m0.003s

Lý do sử dụng lệnh thời gian là để có thể xem giờ. Nhưng nếu bạn nhìn vào kết quả, tổng thời gian chạy không phải là ba giây. Điều này là do SIGALRM tín hiệu từ báo thức (1) khi giây đầu tiên kết thúc, trong khi syscall gây ra bởi chức năng sleep (3) đang chạy. Khi tín hiệu này đến, nó sẽ làm gián đoạn cuộc gọi tổng hợp được bắt đầu cho ngủ (3).

Sử dụng bộ hẹn giờ khoảng thời gian

Cơ chế hẹn giờ khoảng thời gian lần đầu tiên có trong phiên bản 4.2 BSD. Sau đó nó đã được tiêu chuẩn hóa bởi POSIX. Ưu điểm chính của nó so với truyền thống báo thức() phương pháp hẹn giờ dựa trên là:

  • Cung cấp độ phân giải micro giây.
  • Nó cho phép kiểm soát việc đo thời gian chi tiết hơn qua ba chế độ khác nhau.
  • Có thể thiết lập một lần và làm cho nó hoạt động theo định kỳ.
  • Có thể tìm ra nó hiện diện trong bao lâu tại bất kỳ thời điểm nào.

Các nguyên mẫu hàm được sử dụng cho các hoạt động hẹn giờ khoảng thời gian như sau:

#include <sys/time.h>

int setitimer(int which, const struct itimerval *newValue, struct itimerval *oldValue);
int getitimer(int which, struct itimerval *value);

struct itimerval
{
struct timeval itInterval;
struct timeval itValue;
};

struct timeval
{
long tv_sec;
long tv_usec;
};

Nếu bạn muốn thiết lập bộ hẹn giờ ngắt quãng, bạn sẽ cần sử dụng itimerval cấu trúc. Bạn sẽ cần chuyển một giá trị bằng cách sử dụng cấu trúc này làm đối số thứ hai cho settimer hàm số.

Ví dụ: một bộ hẹn giờ khoảng thời gian sẽ thông báo cho ứng dụng của bạn trong 1 giây và sau đó cứ sau 300 mili giây có thể được thiết lập như sau:

struct itimerval newTimer;
struct itimerval oldTimer;

newTimer.itValue.tv_sec = 1;
newTimer.itValue.tv_usec = 0;

newTimer.itInterval.tv_sec = 0;
newTimer.itInterval.tv_usec = 300 * 1000;

setitimer(ITIMER_REAL, &newTimer, &oldTimer);

Nếu có một bộ hẹn giờ khoảng thời gian hoạt động trước khi các giá trị mới được đặt, các giá trị của nó sẽ được chuyển đến địa chỉ biến của itimerval nhập cho tham số thứ ba của hàm.

Bạn có thể thiết lập ba kiểu hẹn giờ khác nhau với cơ chế hẹn giờ khoảng thời gian. Chỉ định loại bộ đếm thời gian trong tham số đầu tiên của setitimer ():

Loại hẹn giờ Dấu hiệu Giải trình
ITIMER_REAL SIGALRM Không phụ thuộc vào thời gian dành cho ứng dụng, được tính trên tổng thời gian đã trôi qua.
ITIMER_VIRTUAL SIGVTALRM Được tính theo thời gian ứng dụng chỉ chạy ở chế độ người dùng.
ITIMER_PROF SIGPROF Được tính trên tổng thời gian dành cho ứng dụng ở cả chế độ người dùng và chế độ hệ thống.

Bạn có thể thấy từ bảng này rằng ITIMER_REAL gõ gửi một SIGALRM tín hiệu, giống như báo thức() hàm số.

Sử dụng bộ hẹn giờ ngắt quãng và báo thức() trong cùng một ứng dụng sẽ gây nhầm lẫn. Mặc dù bạn có thể kiểm tra lần thứ hai trong thời gian còn lại với gettimer ()sẽ không có ý nghĩa nếu sử dụng chúng đồng thời.

Dưới đây là một ví dụ về việc xác định chức năng xử lý tín hiệu với tiêu đề gỡ lỗi:

#include  <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include "./debug.h"

void timer_callback(int signum)
{
struct timeval now;
gettimeofday(&now, NULL);
printf("Signal %d caught on %li.%03li ", signum, now.tv_sec, now.tv_usec / 1000);
}

int main()
{
unsigned int remaining = 3;

struct itimerval new_timer;
struct itimerval old_timer;

new_timer.it_value.tv_sec = 1;
new_timer.it_value.tv_usec = 0;
new_timer.it_interval.tv_sec = 0;
new_timer.it_interval.tv_usec = 300 * 1000;

setitimer(ITIMER_REAL, &new_timer, &old_timer);
signal(SIGALRM, timer_callback);

while (sleep(remaining) != 0)
{
if (errno == EINTR)
debugf("sleep interrupted by signal");
else
errorf("sleep error %s", strerror(errno));
}

return 0;
}


Đoạn mã trên sử dụng ngủ() chức năng chờ trong ba giây. Trong thời gian này, một bộ đếm thời gian chạy, đầu tiên trong một giây, sau đó trong khoảng thời gian 300 mili giây.

Để hiểu rõ hơn, hãy lưu và biên dịch mã mẫu với tên khoảng thời gian.c:

$ gcc -o interval interval.c
$ time ./interval
Signal 14 caught on 1653493614.325
debug: sleep interrupted by signal (main interval.c:36)
Signal 14 caught on 1653493614.625
debug: sleep interrupted by signal (main interval.c:36)
Signal 14 caught on 1653493614.925
debug: sleep interrupted by signal (main interval.c:36)
Signal 14 caught on 1653493615.225
debug: sleep interrupted by signal (main interval.c:36)
Signal 14 caught on 1653493615.525
...

Như bạn có thể thấy từ đầu ra sau khi bộ đếm thời gian chạy, nó sẽ gọi hàm gọi lại sau mỗi 300 mili giây.

Tuy nhiên, sau khi đợi lâu hơn một chút, bạn sẽ nhận thấy rằng ứng dụng không kết thúc. Nó tiếp tục chạy chức năng gọi lại sau mỗi 300 mili giây. Nếu bạn tăng giá trị khoảng thời gian tính bằng mili giây, bạn sẽ thấy rằng ứng dụng kết thúc. Điều này là do khu vực sử dụng của ngủ() hàm số.

Tầm quan trọng của việc sử dụng bộ hẹn giờ trong Linux

Đặc biệt đối với các ứng dụng thời gian thực, cơ chế hẹn giờ có tầm quan trọng lớn. Đây cũng là một giải pháp được sử dụng để tối ưu hóa hiệu suất. Bạn thậm chí có thể sử dụng nó để đo thời gian hoạt động hoặc độ trễ trong ứng dụng của mình. Điều quan trọng là sử dụng cơ chế hẹn giờ để theo dõi thời gian đã trôi qua và các sự kiện chuyển tiếp thời gian.


phụ nữ biên dịch và cài đặt phần mềm trên Linux

Cách biên dịch và cài đặt phần mềm từ nguồn trong Linux

Đọc tiếp


Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *