Báo cáo Đồ án Nguyên lý hệ điều hành
LỜI NÓI ĐẦU
Nguyên lý hệ điều hành là 1 môn học bổ ích giúp sinh viên chúng em hiểu biết
được cơ cấu tổ chức, cũng như việc quản lý, điều phối các tiến trình của hệ thống máy
tính. Qua đó hiểu biết phần nào về phần mềm cơ bản nhất của máy tính là hệ điều hành.
Việc nghiên cứu, hoàn thành đồ án nguyên lý hệ điều hành cũng giúp chúng em được
hiểu rõ hơn nữa về hệ điều hành Linux, 1 hệ điều hành có nhiều tính năng vượt trội và có
triển vọng trong tương lai.
Chúng em xin chân thành cảm ơn sự hướng dẫn của thầy Mai Văn Hà, đã tận tình
chỉ dẫn giúp chúng em hoàn thành được đề tài đồ án này.
TỔNG QUAN ĐỀ TÀI
1.1. Bối cảnh đề tài:
Nhận thấy việc giao tiếp giữa các tiến trình trên linux có thể giúp ta hiểu rõ hơn cơ chế
xử lý, và trao đổi dữ liệu giữa các tiến trình trong hệ điều hành linux. Trong đó việc trao
đổi dữ liệu, giao tiếp qua đường ống pipe theo cơ chế FIFO tương đối dễ hiểu và cũng
phần nào giúp em hiểu được nguyên lý tổ chức hệ điều hành nên chúng em quyết định
chọn đề tài này.
1.2. Mục tiêu đề tài:
Hiểu hơn về việc giao tiếp giữa các tiến trình trong hệ điều hành linux đặc biệt là bằng
đường ống pipe. Nghiên cứu đề tài này sẽ có thể cho ta hiểu được thế nào là pipe và cơ
chế hoạt động của nó.
1.3. Hướng giải quyết:
Đầu tiên phải tìm hiểu cách giao tiếp giữa các tiến trình, là thế nào 2 tiến trình giao tiếp
với nhau thông qua đường ống pipe. Khi giao tiếp bằng pipe này thì vấn đề gì sẽ nảy sinh
ra ( lỗi, hạn chế ). Từ đó tìm ra cách giải quyết và mô phỏng cách sử dụng pipe thông qua
bài toán.
Khi một pipe được thiết lập giữa hai tiến trình, một tiến trình sẽ ghi dữ liệu vào pipe còn
tiến trình kia đọc dữ liệu từ pipe.
SVTH: Hoàng Thị Mai Liên Trang 1
Báo cáo Đồ án Nguyên lý hệ điều hành
Điều trước hết ta phải tạo hai tiến trình cha và con, làm sao để hai tiến trình này giao tiếp
mình miễn phí bằng Internet dưới tên gọi Linux – chữ viết tắt của Linus và Unix. Phiên bản đầu
tiên của Linux là 0.01 được tung ra vào tháng 8/1991.
Các phiên bản đầu tiên có rất nhiều hạn chế. Tuy nhiên, sự kiện các mã nguồn được
truyền bá rộng rãi đã giúp phát triển hệ điều hành rất nhanh. Nhiều năm qua, số lượng các công
ty khai thác đã không ngừng tăng lên. Ngày nay, Linux được phát triển bởi nhiều người rải rác
khắp nơi trên thế giới.
Mặc dù 5 phiên bản đầu tiên của Linux tương đối không ổn định, nhưng phiên bản đầu
tiên được tuyên bố là ổn định (1.0 ) đã được công bố vào khoảng tháng 3/1994. Số phiên bản đi
kèm với kernel có một ý nghĩa đặc trưng bởi vì nó liên quan đến chu kì phát triển. Thực tế, quá
trình phát triển Linux diễn ra theo một chuỗi hai giai đoạn:
Giai đoạn phát triển: ở đây kernel không có độ tin cậy cao và tiến trình là bổ sung chức
năng cho nó, tối ưu hóa nó và thử nghiệm các ý tưởng mới. Giai đoạn này đem lại sự gia tăng số
lượng các phiên bản đánh số lẻ, chẳng hạn như 1.1, 1.3… Đây là thời điểm mà lượng công việc
tối đa được thực hiện trên kernel.
Giai đoạn ổn định: mục đích là tạo ra một kernel càng ổn định càng tốt. Trong trường
hợp này, chỉ cho phép thực hiện các hiệu chỉnh, sửa đổi nhỏ. Số phiên bản của các kernel được
gọi là ổn định là các số chẵn, chẳng hạn 1.0 , 1.2 và mới nhất là 2.2.
Ngày nay, Linux hoàn toàn là một hệ điều hành Unix. Nó ổn định và liên tục phát triển.
Nó không chỉ có khả năng phát triển trên các thiết bị ngoại vi mới nhất trên thị trường ( bộ nhớ
flash quang , đĩa quang … ) mà hiệu năng của nó còn có thể so sánh với một số hệ điều hành
Unix thương mại và thậm chí còn có một số điểm ưu việt hơn. Sau cùng, mặc dù Linux đã có
một khoảng thời gian bị giới hạn trong môi trường các trường đại học, bây giờ nó đang được tiếp
nhận ở các hãng công nghiệp.
.
1.5.2. Các chức năng của hệ điều hành Linux
Hệ điều hành Linux có rất nhiều chức năng và chúng khai thác khả năng của các hệ Unix hiện
đại theo các cách sau :
Đa xử lí: các bộ đa xử lí có thể thực hiện nhiều chương trình đồng thời bất kể sử dụng một hay
nhiều bộ xử lí.
SVTH: Hoàng Thị Mai Liên Trang 3
Về mặt ý niệm, có thể xem như mỗi tiến trình sỡ hữu một bộ xử lý ảo cho riêng nó,
nhưng trong thực tế, chỉ có một bộ xử lý thật sự được chuyển đổi qua lại giữa các tiến trình. Sự
chuyển đổi nhanh chóng này được gọi là sự đa chương (multiprogramming). Hệ điều hành chịu
trách nhiệm sử dụng một thuật toán điều phối để quyết định thời điểm cần dừng hoạt động của
tiến trình đang xử lý để phục vụ một tiến trình khác, và lựa chọn tiến trình tiếp theo sẽ được phục
vụ. Bộ phận thực hiện chức năng này của hệ điều hành được gọi là bộ điều phối (scheduler)
SVTH: Hoàng Thị Mai Liên Trang 4
Báo cáo Đồ án Nguyên lý hệ điều hành
1.6.1. Các trạng thái của tiến trình
Trạng thái của tiến trình tại một thời điểm được xác định bởi hoạt động hiện thời
của tiến trình tại thời điểm đó. Trong quá trình tồn tại, một tiến trình thay đổi trạng thái
do nhiều nguyên nhân như : phải chờ một sự kiện nào đó xảy ra, hay đợi một thao tác
nhập/xuất hoàn tất, buộc phải dừng hoạt động do đã hết thời gian xử lý …
Tại một thời điểm, một tiến trình có thể nhận trong một các trạng thái sau đây :
In execution ( thực hiện ) : Tiến trình đang được bộ xử lý thực hiện.
Ready ( sẵn sàng ): Tiến trình có thể được thực hiện nhưng một tiến trình khác
lại đang chạy.
Suspended (chờ kích hoạt): Tiến trình chờ diễn ra sự kiện ( Ví dụ như đang chờ
nhập hoặc xuất kết thúc).
Zombie (tồn tại) : Tiến trình đã kết thúc thực hiện, nhưng nó vẫn được tham
chiếu trong hệ thống.
Stop (ngừng) : Tiến trình đã bị treo bởi một tiến trình ngoài
Ví dụ, khi có hai người dùng (user), một mang tên là A, một mang tên là B cùng đăng nhập và
chạy chương trình C ( chương trình có nhiệm vụ tìm một chuỗi ký tự trong file) đồng thời, thực
tế hệ điều hành sẽ quản lý và nạp mã của chương trình C vào hai vùng nhớ khác nhau và gọi mỗi
phân vùng như vậy là tiến trình. Hình cho thấy cách phân chia chương trình C thành hai tiến
trình cho hai người dùng khác nhau sử dụng.
Ở hình minh họa, người dùng A chạy chương trình C tìm chuỗi B trong tệp findgirl.txt
$CB findA.txt
Trong khi người dùng B chạy C và tìm chuỗi A trong tệp findboy.txt
$CA findB.txt
Chúng ta nên nhớ rằng hai người dùng A và B có thể ở hai máy tính khác nhau đăng nhập vào
máy chủ Linux và gọi C chạy đồng thời. Hình 2 là hiện trạng không gian bộ nhớ hệ điều hành
Linux khi chạy chương trình C phục vụ người dùng.
SVTH: Hoàng Thị Mai Liên Trang 6
Báo cáo Đồ án Nguyên lý hệ điều hành
Nếu dùng lệnh ps, hệ thống sẽ liệt kê cho bạn thông tin về các tiến trình mà hệ điều hành đang
kiểm soát. Ví dụ với tham số -af , chúng ta có thể thấy các thông tin do ps liệt kê như sau
UID PID PPID C STIME TTY TIME CMD
root 2345 1234 0 Apr11 pts/0 00:00:00 [bash]
root 4345 2342 0 20:44 pts/3 00:00:00 ps –af
A 111 1235 0 20:44 tty1 00:00:00 C B
find…
B 222 1235 0 20:44 tty1 00:00:00 C A
find
…
Mỗi tiến trình được gán cho một định danh để nhận dạng gọi là PID (process identifier). PID
thường là số nguyên dương có giá trị từ 2 – 32768. Khi một tiến trình mới yêu cầu khởi động, hệ
điều hành sẽ chọn lấy một số (chưa bị tiến trình đang chạy nào chiếm giữ) trong khoản số
nguyên trên và cấp phát cho tiến trình mới. Khi tiến trình chấm dứt, hệ thống sẽ thu hồi lại số
PID để cấp phát cho tiến trình mới.
Tiến trình với PID = 1 là tiến trình init, tiến trình init được gọi và chạy ngay khi khởi động hệ
find
…
Trong đó :
• !"#$%&'()*+
• ,-.%/#01.()*2%!3#$-14506%78
19%:);<=(>+
• ,,0)?,-.%/#0@0()*0+
• AB"%:1()*%!3%!06C#9+
• DE1*?)10-FG'()*
• AB-"01#9H,@0()*
CMD : là toàn bộ dòng lệnh khi tiến trình được triệu gọi
1.6.3. Tạo lập tiến trình
Ta có thể gọi một chương trình khác bên trong chương trình đang chạy bằng hàm system().
Hay nói cách khác ta có thể tạo ra một tiến trình mới từ một tiến trình đang chạy. Hàm system()
được khai báo như sau :
Hàm này gọi chuỗi lệnh cmdstr thực thi và
chờ lệnh chấm dứt mới quay về nơi gọi hàm.
Nó tương đương với việc ta gọi shell thực thi
lệnh của hệ thống.
SVTH: Hoàng Thị Mai Liên Trang 8
#include <stdlib.h>
int system( const char *cmdstr);
$sh –c cmdstr
Báo cáo Đồ án Nguyên lý hệ điều hành
system() sẽ trả về mã lỗi 127 nếu như không thể khởi động shell để gọi lệnh cmdstr. Mã lỗi –1
nếu gặp các lỗi khác. Ngược lại mã trả về của system() là mã lỗi do cmdstr sau khi thực thi trả
về.
Ví dụ cách sử dụng hàm system() trong chương trình:
Ví dụ : system.c
Hàm system() đã được sử
#include <stdlib.h>
#include<stdio.h>
int main()
{
printf(“Running ps with system\n”);
system(“ps –ax”);
printf(“Done.\n”);
exit(0);
}
#include<unistd.h>
extrn char **environ;
int execl(const char *path, const char *arg,…);
int execlp(const char *file, const char *arg…);
int execle(const char *path, const char *arg,…,char *const envp[]);
int exect(const char *path, const char *argv[]);
int execv(const char *path, const char *argv[]);
int execvp(const char *path, const char *argv[]);
#include <unistd.h>
#include <stdio.h>
int main()
{
printf(“Running ps with execlp\n”);
execlp(“ps”, “ps”, “-ax”, 0);
printf(“Done. – But you never see this line”);
exit();
}
I()*
J'fork()
)F6K,@0()*0
)F6K)/L
Hàm wait() được gọi trong tiến trình cha sẽ dừng lại
chờ tiến trình con kết thúc trước khi thực hiện tiếp các
lệnh điều khiển trong tiến trình cha. wait() làm cho sự
liên lạc giữa tiến trình cha và tiến trình con trở nên tuần tự. Khi tiến trình con kết thúc hàm sẽ trả
về số PID tương ứng của tiến trình con. Nếu ta truyền thêm đối số stat_loc khác Null cho hàm thì
wait() cũng sẽ trả về trạng thái mà tiến trình con kết thúc trong biến stat_loc. Ta có thể sử dụng
các macro khai báo sẵn trong sys/wait.h để diễn dịch ý nghĩa trạng thái như sau :
WIFEXITED(stat_loc) Trả về trị khác 0 nếu tiến trình con kết
thúc bình thường
WEXITSTATUS(stat_loc) Trả về mã lỗi của tiến trình con
WIFSIGNALED(stat_loc) Trả về trị khác 0 nếu tiến trình con kết
thúc bởi một tín hiệu gửi đến nhưng
không đón bắt và xử lý được.
WTERMSIG(stat_loc) Cho biết số tín hiệu đã hủy tiến trình
con
WIFSTOPPED(stat_loc) Trả về trị khác 0 nếu tiến trình con đã
dừng
WSTOPSIG(stat_loc) Trả về số hiệu của signal
SVTH: Hoàng Thị Mai Liên Trang 11
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
printf(“fork program starting\n”);
pid = fork();
if (pid == -1) perror(“Can not call fork”); // Dữ liệu bị lỗi
else if (pid ==0) printf(“This is the child”);
else printf(“this is the parent”);
nó có thể giao tiếp với nhau, liên lạc với nhau.
Chia sẻ thông tin: Nhiều tiến trình có thể cùng quan tâm đến những dữ liệu nào đó,
do vậy hệ điều hành cần cung cấp một môi trường cho phép sự truy cập đồng thời đến
các dữ liệu chung.
Hợp tác hoàn thành tác vụ: Nhiều tiến trình cùng tham gia thực hiện một công
việc. Hình thức này sẽ đẩy nhanh khả năng xử lý công việc trong hệ thống.
1.7.2. Các cơ chế giao tiếp tiến trình trong Linux
Hệ điều hành Linux cung cấp cho người dùng một số cơ chế giao tiếp giữa các tiến
trình như là:
- Giao tiếp bằng tín hiệu (signals handing).
SVTH: Hoàng Thị Mai Liên Trang 12
)*O )*P
Q#R);K=
Báo cáo Đồ án Nguyên lý hệ điều hành
- Giao tiếp bằng đường ống (pipe).
- Giao tiếp bằng hàng đợi thông điệp (message queue).
- Giao tiếp bằng sử dụng vùng nhớ chia sẻ (share memory).
- Giao tiếp bằng đồng bộ tín hiệu semephore.
- Giao tiếp trao đổi thông qua socket.
1.7.3. Các vấn đề nảy sinh trong giao tiếp giữa các tiến trình
Do mỗi tiến trình sở hữu một không gian địa chỉ riêng biệt, nên các tiến trình không thể
liên lạc trực tiếp dễ dàng mà phải nhờ vào các cơ chế do hệ điều hành cung cấp. Khi cung
cấp cơ chế liên lạc cho các tiến trình, hệ điều hành thường phải tìm giải pháp cho các vấn
đề chính yếu sau:
- Giao tiếp tường minh hay tiềm ẩn (explicit naming/ implicit naming): tiến trình có cần
phải biết tiến trình nào đang trao đổi hay chia sẻ thông tin với nó? Mỗi liên kết được gọi
là tường minh khi được thiết lập rõ ràng, trực tiếp giữa các tiến trình và là tiềm ẩn khi các
tiến trình liên lạc với nhay thông qua một quy ước ngầm nào đó.
- Giao tiếp theo chế độ đồng bộ hay không đồng bộ (blocking/ nonblocking): Khi tiến
trình trao đổi thông tin với một tiến trình khác, các tiến trình có cần phải đợi cho thao tác
kèm theo một số mô tả để ta có thể truy xuất
Hàm này yêu cầu đối số là mảng filedes bao
gồm hai phần tử nguyên dùng để lưu lại số mô tả cho
đường ống trả về sau lời gọi hàm. Nếu hàm thành
công ta có thể dùng hai số mô tả này để thực hiện thao tác đọc/ghi trên đường ống. Phần
tử thứ nhất của mảng được dùng để đọc, trong khi phần tử thứ hai của mảng được dùng
để ghi. Ví dụ về cách gọi hàm pipe() tạo đường ống.
Nếu pipe() thực hiện thành công, đường ống sẽ được tạo ra, pipes[0] là số mô tả
đường ống phía đầu đọc trong khi pipes[1] là số mô tả đường ống phía đầu ghi. Nếu
không tạo được đường ống mã lỗi trả về sẽ là –1.
Trong ví dụ dưới đây, sau khi tạo ra đường ống, ta gọi hàm fork() để tạo ra tiến
trình con. Như ta đã biết, khi nhân đôi tiến trình, bộ mô tả file của tiến trình cha và tiến
trình con có khả năng kế thừa nhau cho nên pipes[] mở bởi tiến trình cha cũng được nhân
bản và sao chép sang tiến trình con. Tiến trình cha sẽ đọc dữ liệu nhập vào từ phía người
dùng và ghi vào đường ống trong khi tiến trình con phía bên kia đường ống tiếp nhận dữ
liệu bằng cách đọc từ đường ống và in ra màn hình.
Ví dụ : oneway_pipe.c
#include <stdio.h>
#include <unistd.h>
/* hàm của tiến trình con */
void do_child(int data_pipe[]{
SVTH: Hoàng Thị Mai Liên Trang 14
#include <unistd.h>
int pipe(int filedes[2])
/* Trước hết định nghĩa mảng bao gồm hai phần tử để chứa số mô tả đường ống */
int pipes[2]
/* Thực hiện tạo đường ống pipe */
int rc = pipe (pipes);
if (rc == -1) { /* tạo đường ống bị lỗi*/
perror(“pipe”);
}
/* Đóng đường ống phía đầu ghi để thông báo phía cuối đường ống dữ
liệu đã ghi hết */
close(data_pipe[1]);
exit(0);
}
/* Chương trình chính*/
int main()
{
int data_pipe[2];
int pid; /* pid của tiến trình con*/
int rc; /* lưu mã lỗi trả về */
/*Tạo đường ống */
rc = pipe(data_pipe);
if (rc == -1) {
perror(“pipe create error”);
exit(1);
}
/* Tách đôi tiến trình con*/
pid = fork();
switch (pid) {
case –1 :
perror (“fork error”);
exit(1);
case 0:
do_child(data_pipe);
default :
doparent(data_pipe);
}
return 0;
trình cha và con. Tiến trình cha gọi fork() để chuyển giao và gắn đường ống vào tiến
trình con, tiến trình con nhận dữ liệu xử lý và chuyển về cho tiến trình cha. Đường ống
tạo ra bằng hàm pipe() được gọi là đường ống vô danh. Nó chỉ được sử dụng giữa tiến
trình cha và con do ta chủ động tạo ra bằng hàm fork(). Một vấn đề đặt ra là, nếu hai tiến
trình không có quan hệ gì với nhau thì có thể sử dụng được cơ chế pipe để giao tiếp với
nhau không? Câu trả lời là có, Linux cho phép ta tạo ra các đường ống đặt tên. Những
đường ống mang tên sẽ nhìn thấy và truy xuất được bởi các tiến trình khác nhau.
* Tạo pipe đặt tên với hàm mkfifo()
Đường ống đặt tên còn được gọi với một tên khác là đối tượng FIFO. Thật sự
đường ống mang tên được biểu diễn như là một file trong hệ thống file của Linux. Ta
SVTH: Hoàng Thị Mai Liên Trang 16
Báo cáo Đồ án Nguyên lý hệ điều hành
dùng lệnh mkfifo để tạo file đường ống với tên chỉ định. Trong chương trình, ta dùng
hàm hệ thống mkfifo() hay mknod(). Khai báo hàm mkfifo() :
#include <sys/types.h>
#include <sys/stat.h>
mkfifo(const char *filename, mode_t mode);
Hàm mkfifo() yêu cầu hai đối số, đối số filename là tên của đường ống cần tạo,
mode là chế độ đọc ghi của đường ống.
Việc tạo đường ống đặt tên không liên quan gì đến các tiến trình. Ta có thể tạo ra
pipe trước khi xây dựng các chương trình sử dụng nó.
SVTH: Hoàng Thị Mai Liên Trang 17
Báo cáo Đồ án Nguyên lý hệ điều hành
CÀI ĐẶT THUẬT TOÁN VÀ TRIỂN KHAI
1.9. Đề tài :
Viết chương trình gốm 2 quá trình. Quá trình thứ nhất cho người dùng nhập vào từ bàn
phím một chuỗi biểu diễn các phép tính gồm các phần tử +, -, (, ). Dộ ưu tiên của các phép tính
trong ngoặc là cao nhất, phép + và – có cùng độ ưu tiên. Ví dụ : 1+7-(8-7+2). Sau đó truyền
chuỗi dữ liệu này sang quá trình thứ 2. Quá trình thứ 2 thực hiện tính toán và trả về cho quá trình
thứ nhất để thể hiện cho người sử dụng biết.
#include <sys/wait.h>
#include <ctype.h>
#include <stdbool.h>
#include <math.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void ChildProcess(int input[2], int output[2]);
void ParentProcess(int input[2], int output[2]);
void xuly(char *ch);
void AddChar(char *ch, char kt);
void AddNumber(char *ch, int n);
void inKt(char kt);
void inNumber(int n);
bool isOperator(char ch);
void errorBt();
int isOther(int i);
void main(void)
{
pid_t pid;
int input_pipe[2];
int output_pipe[2];
int rc, child_status;
rc = pipe(input_pipe);
if(rc ==-1){
perror("\tmain : input_pipe error");
exit(1);
}
rc = pipe(output_pipe);
//Ham xu li bieu thuc vao
xuly(ch);
rc = write(output[1], ch, strlen(ch));
if (rc==-1)
{
perror("Error");
close(output[0]);
close(output[1]);
exit(1);
}
close(input[0]);
close(output[1]);
}
void ParentProcess(int input[2], int output[2])
{
int rc;
char c, ch[100] = "";
close(input[0]);
close(output[1]);
printf("\n\tNhap bieu thuc: "); gets(ch);
rc = write(input[1], ch, strlen(ch));
if (rc==-1)
{
perror("Error");
close(input[0]);
close(input[1]);
exit(1);
}
rc = read(output[0], ch, 100);
if (rc==-1)
kq[++k] = stack_[j ];
stack_[++j] = 'd'; //truong hop nay + la dau
duong
break;
}
case '-':
if(k<0) {
stack_[++j] = 'a'; //truong hop nay - la dau am
break;
}
if(isOperator(ch[i-1])) {
while(j>=0 && (stack_[j]=='a' || stack_[j]=='d'))
kq[++k] = stack_[j ];
stack_[++j] = 'a'; //truong hop nay - la dau am
break;
}
else{
while(j>=0 && (stack_[j]=='+' || stack_[j]=='-'
|| stack_[j]=='*' || stack_[j]=='/' || stack_[j]=='^' || stack_[j]=='a'
|| stack_[j]=='d') ) kq[++k] = stack_[j ];
stack_[++j] = ch[i];
}
break;
case '*':
case '/':
if( (k<0) || isOperator(ch[i-1]) ) {
errorBt();//Bieu thuc loi
return;
SVTH: Hoàng Thị Mai Liên Trang 21
Báo cáo Đồ án Nguyên lý hệ điều hành
if(isdigit(ch[i+1])==0) {
kq[++k] = temp;
temp = 0;
}
}
else i = isOther(i);
}
}
while(j>=0){
kq[++k] = stack_[j ];
}
printf("\n\tDang trung to: %s", ch);
printf("\n\tDang hau to: ");
for(i = 0; i <= k; i++){
switch(kq[i]){
case 'd':
inKt('+');
break;
case 'a':
inKt('-');
break;
case '+':
case '-':
case '*':
SVTH: Hoàng Thị Mai Liên Trang 22
Báo cáo Đồ án Nguyên lý hệ điều hành
case '/':
case '^':
inKt(kq[i]);
break;
case '+':
temp = stack_[j] + stack_[j-1];
stack_[ j] = temp;
break;
case '-':
temp = stack_[j-1] - stack_[j];
stack_[ j] = temp;
break;
case '*':
temp = stack_[j] * stack_[j-1];
stack_[ j] = temp;
break;
case '/':
temp = stack_[j-1] / stack_[j];
stack_[ j] = temp;
break;
default:
stack_[++j] = kq[i];
}
}
if(j!=0) printf("\nTinh toan sai: j = %d",j);
SVTH: Hoàng Thị Mai Liên Trang 23
Báo cáo Đồ án Nguyên lý hệ điều hành
else printf("\n\tKet qua bieu thuc: %d", stack_[0]);
//Bo sung ket qua sau chuoi da nhap
AddChar(ch, '=');
AddNumber(ch, stack_[0]);
}
void AddChar(char *ch, char kt){
ch[strlen(ch)+1] = ch[strlen(ch)];
}while(n);
for( ; i >=0 ; i ){
inKt(a[i]);
}
}
bool isOperator(char ch){
switch(ch){
SVTH: Hoàng Thị Mai Liên Trang 24
Báo cáo Đồ án Nguyên lý hệ điều hành
case '+':
case '-':
case '*':
case '/':
case '^':
return true;
default:
return false;
}
}
void errorBt(){
printf("\n Bieu thuc nhap vao khong dung, khong the tinh duoc!\n\n");
//exit(0);
}
int isOther(int i){
printf("\n\nisOther \n\n");
return i;
}
int mu(int a, int b){
int i = 1, temp = 1;
if(a==0) return 0;