本周學習概況
● 系統調用
● 標準I/O庫
● 進程式控制制
● 處理序間通訊:管道、具名管道、訊息佇列
● 訊號的基本操作
● 線程的基本操作
具體內容如下:
● 系統調用
基本命令
#who
作用: 顯示登陸使用者名稱,終端名,登陸時間
#open
作用 : 開啟一個檔案
標頭檔 #include <fcntl.h>
原型 int open(char *name, int how)
#close
作用:關閉一個檔案
標頭檔: #include <unistd.h>
原型: int close(int fd)
#read
把指定數目的資料讀到緩衝區
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count)
● 標準I/O庫
以下的庫函數均為#include<stdio.h>
開啟和關閉流
FILE* fopen(const char *path, const char *mode);
int fclose(FILE *stream);
每次一個字元的I/O
int getc(FILE *fp)
int fgetc(FILE *fp)
int getchar(void)
int putc(int c, FILE *fp)
int fputc(int c, FILE *fp)
int putchar(int c)
每次一行的I/O
char *fgets(char *buf, int n, FILE *fp)
char *gets(char *buf)
int fputs(const char *str, FILE *fp)
int puts(const char *str)
資料區塊I/O
size_t fread(void *ptr, size_t size, size_t nobj, FILE *fp)
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp)
定位流
long ftell(FILE *fp)
int fseek(FILE *fp, long offset, int whence)
void rewind(FILE *fp)
int fgetpos(FILE *fp, fpos_t *pos)
int fsetpos(FILE *fp, fpos_t *pos)
格式化輸出
int printf(const char *format, …)
int fprintf(FILE *fp, const char *format, …)
int sprintf(char *buf, const char *format, …)
int snprintf(char *buf, size_t n, const char *format,…)
格式化輸入
int scanf(const char *format,…)
int fscanf(FILE *fp, const char *format,…)
int sscanf(const char *buf, const char *format,…)
檔案流的檢測
int feof(FILE *fp)
int ferror(FILE *fp)
●進程式控制制
fork函數:建立一個新進程
#include <unistd.h>
pid_t fork(void)
vfork函數:建立一個新進程
#include <unistd.h>
pid_t vfork(void);
exec函數
int execl(const char *path, const char *arg0, … ,(char *)0 )
int execv(const char *path, char *const argv[])
int execle(const char *path, const char *arg0, … ,(char *)0, char *const envp[] )
int execve(const char *path, char *const argv[], char *const envp[])
int execlp(const char *filename, const char *arg0, …, (char *)0 )
int execvp(const char *filename, char *const argv[])
wait和waitpid函數
#include <sys/wait.h>
pid_t wait(int *status)
pid_t waitpid(pid_t pid, int *status, int options)
exit與_exit函數
#include <stdlib.h>
void exit(int status)
void _exit(int status)
sleep函數
unsigned int sleep(unsigned int sec)
●處理序間通訊
pipe管道的建立
#include <unistd.h>
int pipe(int filedes[2]);
fifo有名管道的建立
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode)
訊息佇列的建立、發送、接收、控制訊息
int msgget(key_t key, int flag);
key要通過函數ftok來產生唯一的值.
key_t ftok(char *pathname, int projid);
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
struct msgbuf{
long mtype; //訊息類型
char mtext[1] //訊息本文
}
ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag)
int msgctl(int msqid, int cmd, struct msqid_ds *buf)
● 訊號的基本操作
kill 傳送訊號
int kill(pid_t pid, int sig)
raise 傳送訊號
int raise(int sig)
alarm 訊號時鐘
unsigned int alarm(unsigned int seconds)
pause 掛起訊號
int pause(void)
signal安裝訊號函數
#include <signal.h>
void (*signal(int signo, void (*func)(int) ) )(int)
訊號集合函式組有如下幾個函數:
初始化訊號集合set並將set設定為空白.
int sigemptyset(sigset_t *set)
初始化訊號集合, 將訊號集合設定為所有訊號的集合
int sigfillset(sigset_t *set)
將訊號signo加入到訊號集合之中.
int sigaddset(sigset_t *set, int signo)
訊號signo從訊號集合中刪除.
int sigdelset(sigset_t *set, int signo)
查詢訊號是否在訊號集合之中
int sigismember(sigset_t *set, int signo)
sigprocmask函數的作用是將指定的訊號集合set加入到進程的訊號阻塞集合之中,或從中刪除。
int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
● 線程的基本操作
線程的建立
#include <pthread.h>
int pthread_creat(pthread_t *thread, pthread_att_t *attr, void *(*start_rtn)(void*), void *arg)
線程的終止
#include <pthread.h>
void pthread_exit(void *rval_ptr);
等待線程的終止
void pthread_join(pthread_t thread, void **rval_ptr)
請求取消同一進程中的其他線程
#include <pthread.h>
void pthread_cancel(pthread_t tid)
線程清理處理常式
#include <pthread.h>
void pthread_cleanup_push(void(*rtn)(void *),void *arg);
void pthread_cleanup_pop(int execute);
定義互斥鎖
#include<pthread.h>
pthread_t mutex;
初始化一個互斥鎖
#include <pthread.h>
Int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
清除一個互斥鎖
int pthread_mutex_destroy( pthread_mutex_t *mutex)
對互斥鎖進行加鎖
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
對互斥鎖解鎖
int pthread_mutex_unlock(pthread_mutex_t *mutex)
訊號量
PV操作
sem_init用於建立一個訊號量,並能初始化它的值
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value)
sem的定義 sem_t sem;
P操作
#include <pthread.h>
int sem_wait(sem_t *sem)
int sem_trywait(sem_t *sem)
V操作
#include <pthread.h>
int sem_post(sem_t *sem)
int sem_getvalue(sem_t *sem)
int sem_destroy(sem_t *sem)
主要的練習:
標準I/O:
練習1:
1.定義一個utmp結構體變數A
2.開啟utmp檔案
3.從utmp檔案中讀取一個結構體變數的內容到A中
4.顯示A.ut_user的內容
5.重複3.4步,知道把utmp檔案的內容讀完。
練習2:
1. fread、fwrite: 用fopen、fread、fclose實現who命令。
2. fseek : 使用fseek定位到utmp檔案的倒數第四個使用者資訊出開始讀取。
5.fsetpos,fgetpos、用fsetpos實現2中的功能
3. sprintf atoi : 使用sprint atoi來實現資料類型的轉換(整形到字串、字元到整形),顯示或用gdb調試,觀察資料。
4. fprintf、fscanf: 使用fprint實現將who命令中的輸出資訊存入檔案。
6.實現IP地址(字串)和整形資料(4個int型資料)之間的轉換:用sscanf 、sprintf 實現
char *host=“192.168.220.5”;
int p1;
int p2;
int p3;
int p4;
轉換後:p1=192; p2=168; p3=220; p4=5
分別實現:(1)IP->整形 (2)整形->IP
進程練習:
1.在主進程中用fork建立另一個進程
在主進程中輸出 “in main process”,並輸出其pid號
在子進程中輸出 “in sub process”,並輸出其pid號
2.在主進程中用vfork 建立另一個進程,在子進程中對全域變數做改變,觀察主進程中的輸出;並與用fork 建立的子進程作比較。
3. 用execl 調用 “ls -a”命令。
例:execl("/bin/ls", "ls","-l","-a",(char *)0);
char argv[]={"ls","-l","-a",(char *)0};
execv("/bin/ls",argv);
4. 寫一個簡單的shell指令碼,並用execl調用。
5. 練習使用wait和waitpid函數,確定主進程在子進程之後退出;
6. 在主進程中建立2個子進程,第一個子進程等待2秒,第二個子進程等待3秒,主進程中用waitpid分別等待兩個子進程退出,輸出一些提示資訊觀察結果。
7. 區別exit(0)和_exit(0)觀察下面兩段程式的執行結果:
int main()
{ printf("this is a test/n")
printf("test exit fun");
exit(0);
}
int main()
{ printf("this is a test/n")
printf("test exit fun");
_exit(0);
}
處理序間通訊
1.用pipe實現“ls –al | more”。涉及的知識點:pipe、dup2、fork。程式名dup.c
2 .fifo 實現本機上的兩終端的聊天通訊。涉及的知識點:mkfiof、 fork 、open、 close、 read 、write、fgets。程式名 chat1.c
Chat2.c
3.訊息佇列實現本機上的兩終端的聊天通訊。涉及的知識點:msgget msgsnd msgrcv msgctl fork fgets.程式名msg_chat.c
訊號的練習:
練習:fork建立2個進程,父進程用系統調用kill()向2個子進程分別發送16和17非強制中斷訊號,在子進程中用signal函數設定訊號處理函數,pause等待到訊號後dosomething結束。程式名:signal_ex.c。
線程的練習:
倉庫,生產者,消費者的練習.涉及的知識點:互斥鎖、PV操作。
程式名:semmphore.c。