Linux驅(qū)動開發(fā)_視頻廣告機(jī)開發(fā)、Linux進(jìn)程編程介紹
昨天完成的任務(wù): Mplayer播放器安裝成功,并且實(shí)現(xiàn)基本使用。
任務(wù)1: 學(xué)習(xí)linux下進(jìn)程編程
1. ?進(jìn)程簡介
進(jìn)程是操作系統(tǒng)調(diào)度的最小單元,線程是進(jìn)程內(nèi)部的執(zhí)行單元,一個(gè)進(jìn)程默認(rèn)有一個(gè)主線程。
進(jìn)程在操作系統(tǒng)里使用PID號作為標(biāo)識符號----查看當(dāng)前終端運(yùn)行的進(jìn)程: ps 。
每個(gè)進(jìn)程之間的資源都是獨(dú)立的。--------進(jìn)程可以自己獨(dú)立的運(yùn)行、帶main----------
? ?今天學(xué)習(xí)的主要任務(wù):
1. 進(jìn)程間通信: 管道(無名管道、命名管道)、消息隊(duì)列、共享內(nèi)存、內(nèi)存映射(mmap)、信號。
2. execl函數(shù)族: 用于啟動一個(gè)新的進(jìn)程,新的進(jìn)程開始執(zhí)行之后,會覆蓋原來進(jìn)程空間。
3. dup2函數(shù): 復(fù)制文件表。------實(shí)現(xiàn)文件描述符重定向。 dup2(fds[1],1);
4. 編寫廣告機(jī)播放器程序
5. 編寫shell腳本,實(shí)現(xiàn)文件同步
1.1 進(jìn)程創(chuàng)建
#include
pid_t fork(void);
功能: 在當(dāng)前進(jìn)程里再創(chuàng)建一個(gè)子進(jìn)程。
函數(shù)返回值: ==0 表示子進(jìn)程,>0表示父進(jìn)程,<0表示出現(xiàn)錯誤
新創(chuàng)建的子進(jìn)程特性: 在fork成功那一刻,會將父進(jìn)程所有的資源全部拷貝一份,重新運(yùn)行。
? ?僵尸進(jìn)程: 子進(jìn)程先退出,父進(jìn)程沒有清理子進(jìn)程的空間。如何清理子進(jìn)程空間? wait();
? ?孤兒進(jìn)程: 父進(jìn)程比子進(jìn)程先退出。避免,就是父進(jìn)程要保證最后退出。
1.2 等待子進(jìn)程退出,并且清理子進(jìn)程空間
#include
#include
pid_t wait(int *status);
函數(shù)功能: 隨機(jī)等待一個(gè)子進(jìn)程退出,并清理子進(jìn)程資源。
返回值: 返回退出的子進(jìn)程PID號。
函數(shù)的形參: int *status可以保存進(jìn)程退出的狀態(tài)。 exit(-1); //結(jié)束當(dāng)前進(jìn)程。
pid_t waitpid(pid_t pid, int *status, int options);
函數(shù): 可以指定特定的PID號。-1表示所有子進(jìn)程。
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char **argv)
{
int pid;
/*創(chuàng)建子進(jìn)程*/
pid=fork();
if(pid==0) //子進(jìn)程
{
printf("子進(jìn)程正常運(yùn)行!....\n");
sleep(1);
/*結(jié)束當(dāng)前進(jìn)程*/
exit(0);
}
else if(pid>0) //父進(jìn)程
{
int state=0; //保存子進(jìn)程退出狀態(tài)值
/*阻塞-等待子進(jìn)程退出*/
wait(&state);
printf("父進(jìn)程提示: 子進(jìn)程已經(jīng)安全退出! 子進(jìn)程退出的狀態(tài)=%d\n",state);
}
else
{
printf("進(jìn)程創(chuàng)建錯誤!");
}
return 0;
}
1.3 終止當(dāng)前進(jìn)程
#include
void _exit(int status);
#include
void _Exit(int status);
#include
void exit(int status);
1.4 管道通信
管道: FIFO文件,特性: 先入先出。
1.4.1 無名管道: 有親緣關(guān)系之間的進(jìn)程才可以使用無名管道進(jìn)程通信。
無名管道這個(gè)FIFO文件沒有實(shí)體。
如果創(chuàng)建無名管道?
#include
int pipe(int pipefd[2]);
函數(shù)形參: 傳入一個(gè)數(shù)組的首地址。
管道創(chuàng)建成功之后: [0]表示(FIFO)無名管道讀端。 [1]表示(FIFO)無名管道寫端。
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char **argv)
{
int pid;
int pipefd[2];
/*創(chuàng)建無名管道*/
pipe(pipefd);
/*創(chuàng)建子進(jìn)程*/
pid=fork();
if(pid==0) //子進(jìn)程
{
printf("子進(jìn)程正常運(yùn)行!....\n");
sleep(1);
char *p="1234567";
write(pipefd[1],p,strlen(p)+1); //向管道的寫端寫入數(shù)據(jù)
/*結(jié)束當(dāng)前進(jìn)程*/
exit(0);
}
else if(pid>0) //父進(jìn)程
{
int state=0; //保存子進(jìn)程退出狀態(tài)值
char buff[100];
read(pipefd[0],buff,100); //從管道的讀端讀取數(shù)據(jù)
printf("父進(jìn)程收到的數(shù)據(jù)=%s\n",buff);
/*阻塞-等待子進(jìn)程退出*/
wait(&state);
printf("父進(jìn)程提示: 子進(jìn)程已經(jīng)安全退出! 子進(jìn)程退出的狀態(tài)=%d\n",state);
}
else
{
printf("進(jìn)程創(chuàng)建錯誤!");
}
return 0;
}
1.4.2 命名管道通信
命名管道可以在任何進(jìn)程間通,因?yàn)槊艿朗且粋€(gè)實(shí)體文件,在磁盤可用找到該FIFO文件。
如何在磁盤上創(chuàng)建管道文件:
#include
#include
int mkfifo(const char *pathname, mode_t mode);
管道文件不能在共享目錄下創(chuàng)建。(掛載的目錄)
1.5 dup2函數(shù)學(xué)習(xí)
#include
int dup2(int oldfd, int newfd);
示例: dup2(fds[1],1); //接下來對文件描述符1的操作都是相當(dāng)于對管道fds[1]操作。
文件描述符在內(nèi)核里對應(yīng)的是一個(gè)文件結(jié)構(gòu)體。
? ?示例1:
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char **argv)
{
int pid;
int pipefd[2];
/*創(chuàng)建無名管道*/
pipe(pipefd);
/*創(chuàng)建子進(jìn)程*/
pid=fork();
if(pid==0) //子進(jìn)程
{
printf("子進(jìn)程正常運(yùn)行!....\n");
dup2(pipefd[1],1);
//pipefd[1]管道寫端,1表示當(dāng)前進(jìn)程的標(biāo)準(zhǔn)輸出
sleep(1);
printf("---1234567---\n");
/*結(jié)束當(dāng)前進(jìn)程*/
exit(0);
}
else if(pid>0) //父進(jìn)程
{
int state=0; //保存子進(jìn)程退出狀態(tài)值
char buff[100];
read(pipefd[0],buff,100); //從管道的讀端讀取數(shù)據(jù)
printf("父進(jìn)程收到的數(shù)據(jù)=%s\n",buff);
/*阻塞-等待子進(jìn)程退出*/
wait(&state);
printf("父進(jìn)程提示: 子進(jìn)程已經(jīng)安全退出! 子進(jìn)程退出的狀態(tài)=%d\n",state);
}
else
{
printf("進(jìn)程創(chuàng)建錯誤!");
}
return 0;
}
? ?示例2: 日志功能制作。
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char **argv)
{
/*1.創(chuàng)建存放日志的文件*/
int fd=open("/log.txt",O_RDWR|O_CREAT,S_IRUSR|S_IWUSR);
/*2. 重定向(將標(biāo)準(zhǔn)輸出重定向到fd)*/
dup2(fd,1);
/*3. 向日志文件寫入數(shù)據(jù)*/
printf("12345\n");
printf("abcd\n");
printf("日志文件測試!\n");
/*4. 關(guān)閉日志文件*/
close(fd);
return 0;
}
1.6 execl 函數(shù)族
#include
extern 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 execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
execl功能介紹: 啟動新的子進(jìn)程,當(dāng)子進(jìn)程啟動成功之后會覆蓋原來的進(jìn)程空間。
Execl函數(shù)族介紹:
1. ?帶p表示可執(zhí)行文件可以從環(huán)境變量里獲取。
2. ?不帶p表示,可執(zhí)行文件需要填絕對路徑。
3. ?帶e表示最后的參數(shù),可以給新進(jìn)程設(shè)置新的環(huán)境變量。
說明: 參數(shù)列表最后面都要加一個(gè)NULL。
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char **argv)
{
/*以ls命令為例子,講解*/
//execl(<可執(zhí)行程序的路徑>,<執(zhí)行的形參列表>,NULL);
//execl("/bin/ls","ls","-l",NULL);
//execlp("ls","ls","-l",NULL);
//char *envp[]={"PATH1=12345",NULL};
//execle("/bin/ls","ls","-l",NULL,envp);
//獲取環(huán)境變量的值: getenv("PATH1");
//char *argvs[]={"ls","-l",NULL};
//execv("/bin/ls",argvs);
char *argvs[]={"ls","-l",NULL};
execvp("ls",argvs);
printf("執(zhí)行失敗!\n");
return 0;
}
//ls -l
1.7 mplayer播放器
Mplayer運(yùn)行有兩個(gè)模式: 1. 主模式 2.從模式
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
獲取標(biāo)準(zhǔn)輸入的數(shù)據(jù)、寫給FIFO文件
*/
void *pthread_func(void *argv)
{
int fd=open("/mplayer_fifo",2);
if(fd<0)
{
printf("FIFO文件打開失敗!\n");
pthread_exit(NULL); //結(jié)束當(dāng)前線程
}
char buff[100];
int len;
while(1)
{
printf("請輸入命令:");
fflush(stdin); //刷新緩沖區(qū)
fgets(buff,100,stdin); //從鍵盤上獲取數(shù)據(jù) get_percent_pos get_file_name
len=strlen(buff); // get_file_name [0~12] [13]='\n'
write(fd,buff,len); // get_file_name '\n'
memset(buff,0,100);
}
}
int main(int argc,char **argv)
{
int pid;
/*1. 創(chuàng)建無名管道*/
int fds[2];
pipe(fds);
/*2. 創(chuàng)建子進(jìn)程*/
pid=fork();
/*子進(jìn)程代碼: mplayer播放器*/
if(pid==0)
{
/*將子進(jìn)程的標(biāo)準(zhǔn)輸出重定向到管道寫端*/
dup2(fds[1],1);
/*啟動子進(jìn)程*/
execlp("mplayer","mplayer","-zoom","-x","800","-y","480","-slave","-quiet","-input","file=/mplayer_fifo","/work/video_file/Video_2018-12-11.wmv",NULL);
}
else /*父進(jìn)程*/
{
char buff[100];
int cnt=0;
/*創(chuàng)建新的線程: 從鍵盤上獲取輸入的數(shù)據(jù),寫給播放器的FIFO文件*/
pthread_t threadID;
pthread_create(&threadID,NULL,pthread_func,NULL);
pthread_detach(threadID); //設(shè)置分離屬性
while(1)
{
/*從管道的讀端讀取數(shù)據(jù): 讀取就是mplayer播放器輸出的數(shù)據(jù)*/
cnt=read(fds[0],buff,100);
buff[cnt]='\0';
printf("播放器輸出的值=%s\n",buff);
}
}
return 0;
}
任務(wù)2: 廣告機(jī)項(xiàng)目
? ?廣告機(jī)項(xiàng)目要求:
廣告機(jī)應(yīng)用場景: 公交站臺、地鐵車廂、銀行前臺大廳、高速公路、公園….
1. ?有些廣告機(jī)只有視頻播放,沒有聲音。
2. ?廣告機(jī)都支持網(wǎng)絡(luò)視頻文件更新---->文件更新使用現(xiàn)成的服務(wù)器: FTP服務(wù)器、NFS服務(wù)器。
(1) ?如何判斷服務(wù)器上那些文件需要下載到本地? 通過shell腳本代碼或者使用C語言。
(2) ?更新的時(shí)間一般是固定的: 20:00 23:00 …… 通過時(shí)間函數(shù)判斷時(shí)間是否到達(dá)。
(3) ?在視頻文件更新的時(shí)候,視頻需要停止播放,可以在屏幕上顯示提示(正在更新…..)。
3. ?廣告機(jī)需要支持自動播放,播放一個(gè)自動切換下一個(gè)、循環(huán)播放。
調(diào)用讀目錄、循環(huán)遍歷目錄、得到視頻文件、mplayer播放器需要使用子進(jìn)程方式啟動。
廣告機(jī): 音量調(diào)整、選擇視頻播放…….都不是廣告機(jī)的功能---是視頻播放器的功能。
#include
Linux 任務(wù)調(diào)度 視頻
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。