Process API
V1.0
email: mesmerli@hotmail.com
前言
本文主要說明 Linux 下,與 Process 相關的API。
system1 執行一個外部程式,並等待外部程式執行完畢後,才繼續執行主程式。
Note: 由 "Done." 的輸出位置可以判斷主程式是否等待外部程式
system1.c
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("Running ps with systemn");
system("ps -ax");
printf("Done.n");
exit(0);
}
System2 同樣執行一個外部程式,但放到背景執行。所以主程式在外部程式上為執行完畢前,便印出 "Done."
system2.c
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("Running ps with systemn");
system("ps -ax &");
printf("Done.n");
exit(0);
}
pexec 所執行的外部程式,取代主程式,所以 "Done." 不會被印出
pexec.c
#include <unistd.h>
#include <stdio.h>
int main()
{
printf("Running ps with execlpn");
execlp("ps", "ps", "-ax", 0);
printf("Done.n");
exit(0);
}
fork1 使用 fork 函數建立兩個程序,fork 函數會給兩個程序不同的 Return value
父程序得到子程序的 Process ID, 子程序得到 0
fork1.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
char *message;
int n;
printf("fork program startingn");
pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
exit(1);
case 0:
message = "This is the child";
n = 5;
break;
default:
message = "This is the parent";
n = 3;
break;
}
for(; n > 0; n--) {
puts(message);
sleep(1);
}
exit(0);
}
使用 wait 函數有以下功能
1. 暫停執行直到子程序結束
2. 取得子程序的返回值
3. 讓作業系統回收子程序所佔用的資源,否成會變成 Zombie Process
wait.c
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
char *message;
int n;
int exit_code;
printf("fork program startingn");
pid = fork();
switch(pid)
{
case -1:
exit(1);
case 0:
message = "This is the child";
n = 5;
exit_code = 37;
break;
default:
message = "This is the parent";
n = 3;
exit_code = 0;
break;
}
for(; n > 0; n--) {
puts(message);
sleep(1);
}
/* This section of the program waits for the child process to finish. */
if(pid) {
int stat_val;
pid_t child_pid;
child_pid = wait(&stat_val);
printf("Child has finished: PID = %dn", child_pid);
if(WIFEXITED(stat_val))
printf("Child exited with code %dn", WEXITSTATUS(stat_val));
else
printf("Child terminated abnormallyn");
}
exit (exit_code);
}
fork2 試著在父程序結束前,讓子程序變成 zombie process
Note: 在副程序結束前,可使用 "ps -al" 觀察
fork2.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
char *message;
int n;
printf("fork program startingn");
pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
exit(1);
case 0:
message = "This is the child";
n = 3;
break;
default:
message = "This is the parent";
n = 5;
break;
}
for(; n > 0; n--) {
puts(message);
sleep(1);
}
exit(0);
}
使用 toupper 函數將小寫變大寫,供 useupper 作為外部程式
upper.c
#include <stdio.h>
#include <ctype.h>
int main()
{
int ch;
while((ch = getchar()) != EOF) {
putchar(toupper(ch));
}
exit(0);
}
利用 freopen 函數轉向 stdin 變成檔案輸入
useupper.c
/* This code, useupper.c, accepts a file name as an argument
and will respond with an error if called incorrectly. */
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
char *filename;
if(argc != 2) {
fprintf(stderr, "usage: useupper filen");
exit(1);
}
filename = argv[1];
/* That done, we reopen the standard input, again checking for any errors as we do so,
and then use execl to call upper. */
if(!freopen(filename, "r", stdin)) {
fprintf(stderr, "could not redirect stdin to file %sn", filename);
exit(2);
}
execl("./upper", "upper", 0);
/* Don't forget that execl replaces the current process;
provided there is no error, the remaining lines are not executed. */
fprintf(stderr, "could not exec upper!n");
exit(3);
}
使用 signal 函數註冊 signal handler
本範例可以讓 signal handler 讓 Ctrl+C 原本中斷功能失效
ctrlc1.c
/* We'll start by writing the function which reacts to the signal
which is passed in the parameter sig.
This is the function we will arrange to be called when a signal occurs.
We print a message, then reset the signal handling for SIGINT
(by default generated by pressing CTRL-C) back to the default behavior.
Let's call this function ouch. */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch(int sig)
{
printf("OUCH! - I got signal %dn", sig);
(void) signal(SIGINT, SIG_DFL);
}
/* The main function has to intercept the SIGINT signal generated when we type Ctrl-C .
For the rest of the time, it just sits in an infinite loop,
printing a message once a second. */
int main()
{
(void) signal(SIGINT, ouch);
while(1) {
printf("Hello World!n");
sleep(1);
}
}
使用 Kill 函數發送 signal 給另外一個 process
pause 函數會暫停 process 執行,直到收到任何一個 signal
alarm.c
/* In alarm.c, the first function, ding, simulates an alarm clock. */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static int alarm_fired = 0;
void ding(int sig)
{
alarm_fired = 1;
}
/* In main, we tell the child process to wait for five seconds
before sending a SIGALRM signal to its parent. */
int main()
{
int pid;
printf("alarm application startingn");
if((pid = fork()) == 0) {
sleep(5);
kill(getppid(), SIGALRM);
exit(0);
}
/* The parent process arranges to catch SIGALRM with a call to signal
and then waits for the inevitable. */
printf("waiting for alarm to go offn");
(void) signal(SIGALRM, ding);
pause();
if (alarm_fired)
printf("Ding!n");
printf("donen");
exit(0);
}
與 signal 註冊函數等效的另一個函數 sigaction
ctrlc2.c
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch(int sig)
{
printf("OUCH! - I got signal %dn", sig);
}
int main()
{
struct sigaction act;
act.sa_handler = ouch;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
while(1) {
printf("Hello World!n");
sleep(1);
}
}
Makefile
# Makefile for applications to demo process API
SYSTEM=system1 system2 pexec
FORK=fork1 wait fork2
FILTER=upper useupper
SIGNALS=ctrlc1 alarm ctrlc2
ALL= $(SYSTEM) $(FORK) $(FILTER) $(SIGNALS)
CROSS_COMPILE = arm-linux-
LINUXDIR = /usr/src/creator/s3c2410/linux
export LINUXDIR
#
# Include the make variables (CC, etc...)
#
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
export AS LD CC CPP AR
CFLAGS= -O0 -gdwarf-2 -DHAVE_CONFIG_H -DFPM_DEFAULT -Dlinux -Dunix -DNDEBUG -D_REENTRANT -I.
#OBJS= mutex_thd1.o
#EXEC = mutex_thd1
#$(EXEC): $(OBJS)
# $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
all: $(ALL)
.c.o:
$(CC) $(CFLAGS) -c -o $@ $<
.S.o:
$(CC) $(AFLAGS) -c -o $@ $<
system1: system1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
system2: system2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
pexec: pexec.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
fork1: fork1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
wait: wait.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
fork2: fork2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
upper: upper.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
useupper: useupper.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
ctrlc1: ctrlc1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
alarm: alarm.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
ctrlc2: ctrlc2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
.PHONY : clean
clean:
rm -f $(EXEC) *.bin *.elf *.o *.s *.gdb *.bak *.*~
0 意見:
張貼留言