Linux程式設計入門 – fork, pthread, and signals

來源:互聯網
上載者:User

 在UNIX程式設計中,學會fork及signal的運用,算是相當基本的功夫。

fork()及signal經常運用在daemon守護神這一類常駐程式,另外像 a4c.tty/yact/chdrv這些中文終端機程式也有用到,一般如 Mozilla/Apache/Squid等大程式幾乎都一定會用到。

雖然在UNIX下的程式寫作,對thread的功能需求並非很大,但thread在現代的 作業系統中,幾乎都已經存在了。pthread是Linux上的thread函數庫,如果您 要在Linux下撰寫多線程式,例如MP3播放程式,熟悉pthread的用法是必要的。

pthread及signal都可以用一大章來討論。在這裡,我只談及最簡單及常用的技 巧,當您熟悉這些基本技巧的運用後,再找一些專門深入探討pthread及signal 程式寫作的書籍來研究。這些進階的寫法,用到的機會較少,將層次分明,學 習速度應該會比較快。

程式分歧fork()

fork()會產生一個與父程式相同的子程式,唯一不同之處在於其process id(pid)。

如果我們要撰寫守護神程式,或是例如網路伺服器,需要多個行程來同時提供 多個連線,可以利用fork()來產生多個相同的行程。
函數宣告

pid_t fork(void);
pid_t vfork(void);

傳回值:

-1 : 失敗。
0 : 子程式。
>0 : 將子程式的process id傳回給父程式。

在Linux下fork()及vfork()是相同的東西。

範例一: fork.c

在這個範例中,我們示範fork()的標準用法。

#include
#include
#include

void main(void)
{
pid_t pid;

printf("hello/n");
pid = fork();

switch (pid) {
case -1: printf("failure!/n"); break;
case 0: printf("I am child!/n"); break;
default: printf("my child is %d/n",pid); break;
}
for (;;) { /* do something here */ }
}

編譯:

gcc -o ex1 fork.c

執行結果:

./ex1 &

hello
my child is 8650
I am child!

我們可以見到,使用fork(),可將一個程式分岐成兩個。在分歧之前的程式碼
只執行一次。

檢驗行程:

ps | grep ex1

8649 p0 R 0:40 ./ex1
8650 p0 R 0:40 ./ex1

8649是父程式的pid,8650則為子程式的pid。 您會需要用到"killall ex1"來殺掉兩個行程。
範例二: daemon.c

在UNIX中,我們一般都利用fork(),來實作所謂的"守護神程式",也就是DOS中 所謂的"常駐程式"。一般的技巧是將父程式結束,而子程式便成為"守護神"。
這個範例中,示範一般標準的daemon寫法。

#include
#include
#include

void main(void)
{
pid_t pid;

pid = fork();

if (pid>0) {
printf("daemon on duty!/n");
exit(0);
} else
if (pid<0) {
printf("Can't fork!/n");
exit(-1);
}

for (;;) {
printf("I am the daemon!/n");
sleep(3);
/* do something your own here */
}

}

編譯:

gcc -o ex2 daemon.c

執行結果:

./ex2

daemon on duty!
I am the daemon!
接下來每三秒鐘,都會出現一個"I am the daemon!"的訊息,這表示您的程式 已經"長駐"在系統中了。

檢驗行程:

ps | grep ex2

8753 p0 S 0:00 ./ex2

注意到在範例一中,我們下的指令為"./ex1 &",而在範例二中為"./ex2",沒有"&"符號。

範例三: lock.c
許多的時候,我們希望"守護神"在系統中只有一個,這時候會需要用到pid lock的技巧。如果您注意到/var/run目錄中的內容,您會發現到有許多的*.pid 檔,觀看其內容都是一些數字,這些數字其實就是該行程的pid。

#include
#include
#include

void main(void)
{
FILE *fp;
pid_t pid;

exit(-1);
}

act.sa_handler = quit;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGTERM,&act,NULL);
sigaction(SIGHUP,&act,NULL);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGUSR2,&act,NULL);

for (;;) {
sleep(3);
}
}

編譯:

gcc -o ex1 lock.c

執行

./ex1

daemon on duty!

送訊號

我們先找出該守護神程式的pid

PID=`cat /var/run/lock.pid`

接下來利用kill來送訊號

kill  $PID

Receive signal 15

程式將會結束,並且/var/run/lock.pid將會被刪除掉,以便下一次daemon再啟動。注意到如果quit函數內,沒有放exit(),程式將永遠殺不掉。

接下來送一些其它的訊號試試看。
./ex1
PID=`cat /var/run/lock.pid`
kill -HUP  $PID

Receive signal 1

您可以自行試試
kill -INT  $PID
kill -QUIT  $PID
kill -ILL  $PID
.
.
.
等等這些訊號,看看他們的結果如何。

訊號的定義

在/usr/include/signum.h中有各種訊號的定義
#define SIGHUP 1 /* Hangup (POSIX). */
#define SIGINT 2 /* Interrupt (ANSI). */
#define SIGQUIT 3 /* Quit (POSIX). */
#define SIGILL 4 /* Illegal instruction (ANSI). */
#define SIGTRAP 5 /* Trace trap (POSIX). */
#define SIGABRT 6 /* Abort (ANSI). */
#define SIGIOT 6 /* IOT trap (4.2 BSD). */
#define SIGBUS 7 /* BUS error (4.2 BSD). */
#define SIGFPE 8 /* Floating-point exception (ANSI).
*/
#define SIGKILL 9 /* Kill, unblockable (POSIX). */
#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */

#define SIGSEGV 11 /* Segmentation violation (ANSI). */

#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */

#define SIGPIPE 13 /* Broken pipe (POSIX). */
#define SIGALRM 14 /* Alarm clock (POSIX). */
#define SIGTERM 15 /* Termination (ANSI). */
#define SIGSTKFLT 16 /* ??? */
#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
#define SIGCHLD 17 /* Child status has changed (POSIX).
*/
#define SIGCONT 18 /* Continue (POSIX). */
#define SIGSTOP 19 /* Stop, unblockable (POSIX). */
#define SIGTSTP 20 /* Keyboard stop (POSIX). */
#define SIGTTIN 21 /* Background read from tty (POSIX).
*/
#define SIGTTOU 22 /* Background write to tty (POSIX).
*/
#define SIGURG 23 /* Urgent condition on socket (4.2
BSD). */
#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */
#define SIGXFSZ 25 /* File size limit exceeded (4.2
BSD). */
#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */

#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD).
*/
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun).
*/
#define SIGPOLL SIGIO /* Pollable event occurred (System
V). */
#define SIGIO 29 /* I/O now possible (4.2 BSD). */
#define SIGPWR 30 /* Power failure restart (System V).
*/
#define SIGUNUSED 31

函數宣告:

Signal Operators

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);

Signal Handling Functions

int sigaction(int signum, const struct sigaction *act,struct
sigaction *oldact);
int sigprocmask(int how, const sigset_t *set, sigset_t
*oldset);
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *mask);

Structure Signal Action
struct sigaction {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}

引用:http://www.chinalinuxpub.com/read.php?wid=102

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.