Mặc dù việc viết phần mềm cho máy tính nhúng thoạt đầu
nghe có vẻ đơn giản, đặc biệt là với các lập trình viên dày
dạn kinh nghiệm, tuy nhiên có những trở ngại mà họ cần phải
biết cách tránh:
(1) Sử dụng quá nhiều bộ nhớ flash của máy tính nhúng,
(2) Rò rỉ bộ nhớ do bộ nhớ động không sử dụng đến không
được tháo ra
11 trang |
Chia sẻ: tranhoai21 | Lượt xem: 1272 | Lượt tải: 0
Bạn đang xem nội dung tài liệu Tránh sự cố trong lập trình ứng dụng nhúng, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
Tránh sự cố trong lập trình
ứng dụng nhúng
Mặc dù việc viết phần mềm cho máy tính nhúng thoạt đầu
nghe có vẻ đơn giản, đặc biệt là với các lập trình viên dày
dạn kinh nghiệm, tuy nhiên có những trở ngại mà họ cần phải
biết cách tránh:
(1) Sử dụng quá nhiều bộ nhớ flash của máy tính nhúng,
(2) Rò rỉ bộ nhớ do bộ nhớ động không sử dụng đến không
được tháo ra
(3) Tạo ra các ứng dụng không lường được các lỗi có thể xảy
ra.
Do các hệ thống nhúng thường phải hoạt động mà không có
giám sát đồng thời trong một thời gian dài, máy tính nhúng
thường được đặt ở xa nơi đi lại, một trong những mục đích
chính của người lập trình hệ thống nhúng là bảo vệ độ ổn
định của hệ thống.
Embedded PC và PC-khác biệt ở bộ nhớ
Vấn đề lớn nhất với việc viết code cho máy tính nhúng là
hiểu sai vai trò của máy tính nhúng. Điều này đặc biệt đúng
đối với người phát triển phần mềm lại là những người lập
trình PC có kinh nghiệm. Trong khi đó, PC hiện đại cực
nhanh và ứng dụng của PC có thể tận dụng được lượng bộ
nhớ trên một PC điển hình, các hệ thống nhúng lại cung cấp
nguồn bộ nhớ có hạn. Trên thực tế, người lập trình hệ thống
nhúng thường gặp rắc rối khi ứng dụng của họ trở nên thiếu
ổn định, không nhận ra rằng vấn đề có liên quan đến bộ nhớ.
Sau đây là một ví dụ đơn giản. Khi viết phần mềm cho các
ứng dụng PC, sẽ là bình thường khi viết 100 MB dữ liệu lên
đĩa cứng 1 GB. So sánh điều này với việc viết 10 MB dữ liệu
lên ổ flash 15 MB cho một ứng dụng nhúng. Mặc dù chỉ sử
dụng 2/3 dung lượng có sẵn, vẫn cần thận trọng để tránh
những sự cố xảy ra, viết dữ liệu nhiều lần cùng một lúc sẽ
dẫn đến “khóa chết” trong ổ flash. Nguyên nhân là do các
thiết bị bộ nhớ flash có vòng đời hoạt động ghi dữ liệu hạn
chế, và do nhiều vùng của bộ nhớ flash sẽ thường không
hỏng cùng lúc, thiết bị bộ nhớ flash sẽ vẫn hoạt động cho tới
khi số lượng bộ nhớ còn dùng được bị xuống cấp dưới mức
cần thiết để chạy ứng dụng. Khi điều đó xảy ra, ứng dụng của
bạn sẽ trở nên thiếu ổn định và sau đó là hỏng.
Cách tốt nhất để sử dụng ổ nhớ flash của một máy tính nhúng
là lưu các file chương trình trên đĩa và lưu dữ liệu được tạo ra
bởi chương trình trên CF card hay SD card mở rộng. Card
mở rộng đem đến dung lượng lưu trữ lớn hơn và cùng lúc đó
tránh được vấn đề vòng đời ổ cứng. Nếu vì một số lý do bạn
phải sử dụng bộ nhớ flash để lưu trữ dữ liệu, chúng tôi muốn
khuyên bạn rằng bạn nên sử dụng một nửa dung lượng flash.
Rò rỉ bộ nhớ
Một sự cố khác cần tránh là rò rỉ bộ nhớ. Máy tính nhúng
thực sự nhạy với việc sử dụng bộ nhớ và việc rò rỉ bộ nhớ
làm giảm công suất hệ thống do việc phân trang bộ nhớ tăng
cao khi các chương trình khác nhau tìm cách chiếm bộ nhớ
sẵn có.
Vấn đề rò rỉ bộ nhớ cũng có thể xuất hiện khi bộ xử lí file
không được sử dụng hay bộ mô tả không được đóng lại.
Trong các ứng dụng truyền thông, mỗi kết nối TCP hay serial
phải liên quan tới một bộ mô tả file chiếm một lượng bộ
nhớ.
Khi bộ mô tả file không được đóng đúng cách và kết nối
được thiết lập đi thiết lập lại nhiều lần, việc tiêu tốn bộ nhớ
thậm chí sẽ dẫn đến rò rỉ bộ nhớ.
Để tránh rò rỉ bộ nhớ, người phát triển phần mềm phải chú ý
chương trình của họ xử lí và sử dụng bộ nhớ như thế nào.
Ngoài ra, các ứng dụng phải được xây dựng thật tốt.
Việc lập trình đòi hỏi một thiết kế từ trên xuống và thực hiện
từ dưới lên. Ứng dụng được phân ra thành các module phân
lớp được tách biệt càng nhiều càng tốt, mỗi module lại được
phân ra thêm thành nhiều chức năng. Trong giai đoạn thực
hiện, bạn nên xây dựng các chức năng của mình trước khi kết
hợp chúng để tạo ra một module hoàn chỉnh.
Lý tưởng hơn là, các chức năng trong một module chiếm
dung lượng ít nhất khi sinh ra, từ đầu vào/đầu ra, và khi
module chết. Đoạn code sau đây phân tích một thí dụ như
thế.
typedef struct _YYYCONN
{
int fd;
char *packet_data;
int packet_size;
} YYYCONN;
/* the death of a module */
void yyy_close(YYYCONN *con)
{
if (con)
{
if (con->fd > 0) close(con->fd); /* close the
file descriptor */
if (con->packet_data) free(con->packet_data);
/* free the data buffer */
free(con); /* be sure to structure body */
}
}
/* the birth of a module */
YYYCONN* yyy_open(char *host, int port)
{
int fd;
YYYCONN *con;
con = (YYYCONN *) malloc(sizeof(YYYCONN)); /*
memory allocation */
if (con==NULL)
return NULL:
con->fd = make_tcp_client(host, port); /* API call to
connect to a TCP server */
If (con->fd < 0)
{
yyy_close(con) ;
return NULL;
}
con->packet_data = (char*) malloc(1024); /* memory
allocation */
if (con->packet_data==NULL)
{
yyy_close(con) ;
return NULL;
}
con->packet_size=0;
return con;
}
Chức năng yyy_open tạo ra module kết nối TCP cùng với
một bộ mô tả file mở. Bản thân module và dữ liệu thành viên
của nó được phân vùng trong bộ nhớ. Khi hủy module, chúng
ta gọi chức năng function yyy_close, module được thiết kế để
đóng bộ mô tả file và sau đó giải phóng bộ nhớ được phân
bổ. Để quản lí nhiều module kết nối chúng ta cần thực hiện
trên khu vực toàn cầu, đây có thể là một chuỗi hay là một
danh sách được liên kết để theo dõi các module này. Một số
chức năng quản lí sau đây cũng có thể được cần đến:
y yyy_connection_add: thêm một kết nối vào danh sách toàn
cầu.
y yyy_connection_remove: xóa kết nối từ danh sách toàn
cầu.
y yyy_connection_lookup: tìm kiếm một kết nối cụ thể.
Xử lí ngoại lệ
Chủ đề cuối cùng của bài này là tính bền vững, điều mà đôi
khi chúng ta nên cố gắng đạt được cho các ứng dụng của
mình. Mọi ngoại lệ có thể xảy ra phải được xử lí một cách
cẩn thận. Phân đoạn mã sau đây là một ví dụ:
while(1)
{
if (select(fd+1, read_fds, NULL, NULL, NULL) > 0)
{
;
}
}
Thí dụ này giả định rằng kết nối sau bộ mô tả file, fd luôn
luôn duy trì hoạt động. Tuy nhiên, kết nối có thể bị ngắt một
cách cố tình bởi bên đồng đẳng, trong trường này chức năng
“lựa chọn” sẽ ngay tức thì quay trở về -1. Chương trình sau
đó sẽ tiêu thụ điện CPU và sẽ không quay lại trạng thái bình
thường.
Kết luận
Người lập trình không biết cách tránh 3 sự cố như trên sẽ gặp
vấn đề về tính ổn định, ngăn các ứng dụng hoạt động lâu dài.
Những vấn đề này có thể khó giải quyết, đặc biệt khi một dự
án đang chịu sức ép để sẵn sàng đưa ra thị trường sớm nhất
có thể.” Vì lí do này, hầu hết những người phát triển đều sử
dụng một bộ định thời giám sát để chạy đồng thời với các
ứng dụng của mình. Nếu dung lượng bộ nhớ sẵn có xuống
quá thấp, hay chương trình rơi vào tình trạng không như
mong đợi, bộ định thời giám sát sẽ không được làm mới và
phần còn lại của hệ thống sẽ được khởi động.