?? linux.txt
字號(hào):
printf("The variable is now %d\n", variable);
if (read(fd, &tempch, 1) < 1) {
perror("File Read Error");
exit(1);
}
printf("We could read from the file\n");
return 0;
}
運(yùn)行輸出:
The variable is now 42
File Read Error
程序的輸出結(jié)果告訴我們,子進(jìn)程將文件關(guān)閉并將變量修改(調(diào)用clone時(shí)用到的CLONE_VM、CLONE_FILES標(biāo)志將使得變量和文件描述符表被共享),父進(jìn)程隨即就感覺到了,這就是clone的特點(diǎn)。
sleep
函數(shù)調(diào)用sleep可以用來使進(jìn)程掛起指定的秒數(shù),該函數(shù)的原型為:
unsigned int sleep(unsigned int seconds);
該函數(shù)調(diào)用使得進(jìn)程掛起一個(gè)指定的時(shí)間,如果指定掛起的時(shí)間到了,該調(diào)用返回0;如果該函數(shù)調(diào)用被信號(hào)所打斷,則返回剩余掛起的時(shí)間數(shù)(指定的時(shí)間減去已經(jīng)掛起的時(shí)間)。
exit
系統(tǒng)調(diào)用exit的功能是終止本進(jìn)程,其函數(shù)原型為:
void _exit(int status);
_exit會(huì)立即終止發(fā)出調(diào)用的進(jìn)程,所有屬于該進(jìn)程的文件描述符都關(guān)閉。參數(shù)status作為退出的狀態(tài)值返回父進(jìn)程,在父進(jìn)程中通過系統(tǒng)調(diào)用wait可獲得此值。
wait
wait系統(tǒng)調(diào)用包括:
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
wait的作用為發(fā)出調(diào)用的進(jìn)程只要有子進(jìn)程,就睡眠到它們中的一個(gè)終止為止; waitpid等待由參數(shù)pid指定的子進(jìn)程退出。
Linux下的C編程實(shí)戰(zhàn)之四
2007-11-06 14:37作者:宋寶華出處:天極網(wǎng)軟件頻道責(zé)任編輯:方舟 1.Linux“線程”
Linux內(nèi)核只提供了輕量進(jìn)程的支持,未實(shí)現(xiàn)線程模型,但Linux盡最大努力優(yōu)化了進(jìn)程的調(diào)度開銷,這在一定程度上彌補(bǔ)無線程的缺陷。Linux用一個(gè)核心進(jìn)程(輕量進(jìn)程)對(duì)應(yīng)一個(gè)線程,將線程調(diào)度等同于進(jìn)程調(diào)度,交給核心完成。
筆者曾經(jīng)在《基于嵌入式操作系統(tǒng)VxWorks的多任務(wù)并發(fā)程序設(shè)計(jì)》(《軟件報(bào)》2006年第5~12期)中詳細(xì)敘述了進(jìn)程和線程的區(qū)別,并曾經(jīng)說明Linux是一種“多進(jìn)程單線程”的操作系統(tǒng)。Linux本身只有進(jìn)程的概念,而其所謂的“線程”本質(zhì)上在內(nèi)核里仍然是進(jìn)程。大家知道,進(jìn)程是資源分配的單位,同一進(jìn)程中的多個(gè)線程共享該進(jìn)程的資源(如作為共享內(nèi)存的全局變量)。Linux中所謂的“線程”只是在被創(chuàng)建的時(shí)候“克隆”(clone)了父進(jìn)程的資源,因此,clone出來的進(jìn)程表現(xiàn)為“線程”,這一點(diǎn)一定要弄清楚。因此,Linux“線程”這個(gè)概念只有在打冒號(hào)的情況下才是最準(zhǔn)確的,可惜的是幾乎沒有書籍留心去強(qiáng)調(diào)這一點(diǎn)。
目前Linux中最流行的線程機(jī)制為L(zhǎng)inuxThreads,所采用的就是線程-進(jìn)程“一對(duì)一”模型,調(diào)度交給核心,而在用戶級(jí)實(shí)現(xiàn)一個(gè)包括信號(hào)處理在內(nèi)的線程管理機(jī)制。LinuxThreads由Xavier Leroy (Xavier.Leroy@inria.fr)負(fù)責(zé)開發(fā)完成,并已綁定在GLIBC中發(fā)行,它實(shí)現(xiàn)了一種BiCapitalized面向Linux的Posix 1003.1c “pthread”標(biāo)準(zhǔn)接口。Linuxthread可以支持Intel、Alpha、MIPS等平臺(tái)上的多處理器系統(tǒng)。
按照POSIX 1003.1c 標(biāo)準(zhǔn)編寫的程序與Linuxthread 庫(kù)相鏈接即可支持Linux平臺(tái)上的多線程,在程序中需包含頭文件pthread. h,在編譯鏈接時(shí)使用命令:
gcc -D -REENTRANT -lpthread xxx. c
其中-REENTRANT宏使得相關(guān)庫(kù)函數(shù)(如stdio.h、errno.h中函數(shù)) 是可重入的、線程安全的(thread-safe),-lpthread則意味著鏈接庫(kù)目錄下的libpthread.a或libpthread.so文件。使用Linuxthread庫(kù)需要2.0以上版本的Linux內(nèi)核及相應(yīng)版本的C庫(kù)(libc 5.2.18、libc 5.4.12、libc 6)。
2.“線程”控制
線程創(chuàng)建
進(jìn)程被創(chuàng)建時(shí),系統(tǒng)會(huì)為其創(chuàng)建一個(gè)主線程,而要在進(jìn)程中創(chuàng)建新的線程,則可以調(diào)用pthread_create:
pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(start_routine)(void*), void *arg);
start_routine為新線程的入口函數(shù),arg為傳遞給start_routine的參數(shù)。
每個(gè)線程都有自己的線程ID,以便在進(jìn)程內(nèi)區(qū)分。線程ID在pthread_create調(diào)用時(shí)回返給創(chuàng)建線程的調(diào)用者;一個(gè)線程也可以在創(chuàng)建后使用pthread_self()調(diào)用獲取自己的線程ID:
pthread_self (void) ;
線程退出
線程的退出方式有三:
(1)執(zhí)行完成后隱式退出;
(2)由線程本身顯示調(diào)用pthread_exit 函數(shù)退出;
pthread_exit (void * retval) ;
(3)被其他線程用pthread_cance函數(shù)終止:
pthread_cance (pthread_t thread) ;
在某線程中調(diào)用此函數(shù),可以終止由參數(shù)thread 指定的線程。
如果一個(gè)線程要等待另一個(gè)線程的終止,可以使用pthread_join函數(shù),該函數(shù)的作用是調(diào)用pthread_join的線程將被掛起直到線程ID為參數(shù)thread的線程終止:
pthread_join (pthread_t thread, void** threadreturn);
Linux下的C編程實(shí)戰(zhàn)之五
2007-11-09 08:41作者:宋寶華出處:天極網(wǎng)軟件頻道責(zé)任編輯:方舟 1.引言
設(shè)備驅(qū)動(dòng)程序是操作系統(tǒng)內(nèi)核和機(jī)器硬件之間的接口,它為應(yīng)用程序屏蔽硬件的細(xì)節(jié),一般來說,Linux的設(shè)備驅(qū)動(dòng)程序需要完成如下功能:
(1)初始化設(shè)備;
(2)提供各類設(shè)備服務(wù);
(3)負(fù)責(zé)內(nèi)核和設(shè)備之間的數(shù)據(jù)交換;
(4)檢測(cè)和處理設(shè)備工作過程中出現(xiàn)的錯(cuò)誤。
妙不可言的是,Linux下的設(shè)備驅(qū)動(dòng)程序被組織為一組完成不同任務(wù)的函數(shù)的集合,通過這些函數(shù)使得Windows的設(shè)備操作猶如文件一般。在應(yīng)用程序看來,硬件設(shè)備只是一個(gè)設(shè)備文件,應(yīng)用程序可以象操作普通文件一樣對(duì)硬件設(shè)備進(jìn)行操作。本系列文章的第2章文件系統(tǒng)編程中已經(jīng)看到了這些函數(shù)的真面目,它們就是open ()、close ()、read ()、write () 等。
Linux主要將設(shè)備分為二類:字符設(shè)備和塊設(shè)備(當(dāng)然網(wǎng)絡(luò)設(shè)備及USB等其它設(shè)備的驅(qū)動(dòng)編寫方法又稍有不同)。這兩類設(shè)備的不同點(diǎn)在于:在對(duì)字符設(shè)備發(fā)出讀/寫請(qǐng)求時(shí),實(shí)際的硬件I/O一般就緊接著發(fā)生了,而塊設(shè)備則不然,它利用一塊系統(tǒng)內(nèi)存作緩沖區(qū),當(dāng)用戶進(jìn)程對(duì)設(shè)備請(qǐng)求能滿足用戶的要求,就返回請(qǐng)求的數(shù)據(jù),如果不能,就調(diào)用請(qǐng)求函數(shù)來進(jìn)行實(shí)際的I/O操作。塊設(shè)備主要針對(duì)磁盤等慢速設(shè)備。以字符設(shè)備的驅(qū)動(dòng)較為簡(jiǎn)單,因此本章主要闡述字符設(shè)備的驅(qū)動(dòng)編寫。
2.驅(qū)動(dòng)模塊函數(shù)
init 函數(shù)用來完成對(duì)所控設(shè)備的初始化工作,并調(diào)用register_chrdev() 函數(shù)注冊(cè)字符設(shè)備。假設(shè)有一字符設(shè)備“exampledev”,則其init 函數(shù)為:
void exampledev_init(void)
{
if (register_chrdev(MAJOR_NUM, " exampledev ", &exampledev_fops))
TRACE_TXT("Device exampledev driver registered error");
else
TRACE_TXT("Device exampledev driver registered successfully");
…//設(shè)備初始化
}
其中,register_chrdev函數(shù)中的參數(shù)MAJOR_NUM為主設(shè)備號(hào),“exampledev”為設(shè)備名,exampledev_fops為包含基本函數(shù)入口點(diǎn)的結(jié)構(gòu)體,類型為file_operations。當(dāng)執(zhí)行exampledev_init時(shí),它將調(diào)用內(nèi)核函數(shù)register_chrdev,把驅(qū)動(dòng)程序的基本入口點(diǎn)指針存放在內(nèi)核的字符設(shè)備地址表中,在用戶進(jìn)程對(duì)該設(shè)備執(zhí)行系統(tǒng)調(diào)用時(shí)提供入口地址。
file_operations結(jié)構(gòu)體定義為:
struct file_operations
{
int (*lseek)();
int (*read)();
int (*write)();
int (*readdir)();
int (*select)();
int (*ioctl)();
int (*mmap)();
int (*open)();
void(*release)();
int (*fsync)();
int (*fasync)();
int (*check_media_change)();
void(*revalidate)();
};
大多數(shù)的驅(qū)動(dòng)程序只是利用了其中的一部分,對(duì)于驅(qū)動(dòng)程序中無需提供的功能,只需要把相應(yīng)位置的值設(shè)為NULL。對(duì)于字符設(shè)備來說,要提供的主要入口有:open ()、release ()、read ()、write ()、ioctl ()。
open()函數(shù) 對(duì)設(shè)備特殊文件進(jìn)行open()系統(tǒng)調(diào)用時(shí),將調(diào)用驅(qū)動(dòng)程序的open () 函數(shù):
int open(struct inode * inode ,struct file * file);
其中參數(shù)inode為設(shè)備特殊文件的inode (索引結(jié)點(diǎn)) 結(jié)構(gòu)的指針,參數(shù)file是指向這一設(shè)備的文件結(jié)構(gòu)的指針。open()的主要任務(wù)是確定硬件處在就緒狀態(tài)、驗(yàn)證次設(shè)備號(hào)的合法性(次設(shè)備號(hào)可以用MINOR(inode-> i - rdev) 取得)、控制使用設(shè)備的進(jìn)程數(shù)、根據(jù)執(zhí)行情況返回狀態(tài)碼(0表示成功,負(fù)數(shù)表示存在錯(cuò)誤) 等;
release()函數(shù) 當(dāng)最后一個(gè)打開設(shè)備的用戶進(jìn)程執(zhí)行close ()系統(tǒng)調(diào)用時(shí),內(nèi)核將調(diào)用驅(qū)動(dòng)程序的release () 函數(shù):
void release (struct inode * inode ,struct file * file) ;
release 函數(shù)的主要任務(wù)是清理未結(jié)束的輸入/輸出操作、釋放資源、用戶自定義排他標(biāo)志的復(fù)位等。
read()函數(shù) 當(dāng)對(duì)設(shè)備特殊文件進(jìn)行read() 系統(tǒng)調(diào)用時(shí),將調(diào)用驅(qū)動(dòng)程序read() 函數(shù):
void read(struct inode * inode ,struct file * file ,char * buf ,int count) ;
參數(shù)buf是指向用戶空間緩沖區(qū)的指針,由用戶進(jìn)程給出,count 為用戶進(jìn)程要求讀取的字節(jié)數(shù),也由用戶給出。
read() 函數(shù)的功能就是從硬設(shè)備或內(nèi)核內(nèi)存中讀取或復(fù)制count個(gè)字節(jié)到buf 指定的緩沖區(qū)中。在復(fù)制數(shù)據(jù)時(shí)要注意,驅(qū)動(dòng)程序運(yùn)行在內(nèi)核中,而buf指定的緩沖區(qū)在用戶內(nèi)存區(qū)中,是不能直接在內(nèi)核中訪問使用的,因此,必須使用特殊的復(fù)制函數(shù)來完成復(fù)制工作,這些函數(shù)在<asm/ segment.h>中定義:
void put_user_byte (char data_byte ,char * u_addr) ;
void put_user_word (short data_word ,short * u_addr) ;
void put_user_long(long data_long ,long * u_addr) ;
void memcpy_tofs (void * u_addr ,void * k_addr ,unsigned long cnt) ;
參數(shù)u_addr為用戶空間地址,k_addr 為內(nèi)核空間地址,cnt為字節(jié)數(shù)。
write( ) 函數(shù) 當(dāng)設(shè)備特殊文件進(jìn)行write () 系統(tǒng)調(diào)用時(shí),將調(diào)用驅(qū)動(dòng)程序的write () 函數(shù):
void write (struct inode * inode ,struct file * file ,char * buf ,int count) ;
write ()的功能是將參數(shù)buf 指定的緩沖區(qū)中的count 個(gè)字節(jié)內(nèi)容復(fù)制到硬件或內(nèi)核內(nèi)存中,和read() 一樣,復(fù)制工作也需要由特殊函數(shù)來完成:
unsigned char_get_user_byte (char * u_addr) ;
unsigned char_get_user_word (short * u_addr) ;
unsigned char_get_user_long(long * u_addr) ;
unsigned memcpy_fromfs(void * k_addr ,void * u_addr ,unsigned long cnt) ;
ioctl() 函數(shù) 該函數(shù)是特殊的控制函數(shù),可以通過它向設(shè)備傳遞控制信息或從設(shè)備取得狀態(tài)信息,函數(shù)原型為:
int ioctl (struct inode * inode ,struct file * file ,unsigned int cmd ,unsigned long arg);
參數(shù)cmd為設(shè)備驅(qū)動(dòng)程序要執(zhí)行的命令的代碼,由用戶自定義,參數(shù)arg 為相應(yīng)的命令提供參數(shù),類型可以是整型、指針等。
同樣,在驅(qū)動(dòng)程序中,這些函數(shù)的定義也必須符合命名規(guī)則,按照本文約定,設(shè)備“exampledev”的驅(qū)動(dòng)程序的這些函數(shù)應(yīng)分別命名為exampledev_open、exampledev_ release、exampledev_read、exampledev_write、exampledev_ioctl,因此設(shè)備“exampledev”的基本入口點(diǎn)結(jié)構(gòu)變量exampledev_fops 賦值如下:
struct file_operations exampledev_fops {
NULL ,
exampledev_read ,
exampledev_write ,
NULL ,
NULL ,
exampledev_ioctl ,
NULL ,
exampledev_open ,
exampledev_release ,
NULL ,
NULL ,
NULL ,
NULL
} ;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -