– Ch4 Linux System Programming Process & IPC Jianjian SONG
Download
Report
Transcript – Ch4 Linux System Programming Process & IPC Jianjian SONG
Ch4 Linux System Programming
– Process & IPC
Jianjian SONG
Software Institute, Nanjing
University
Oct, 2004
Content
1. Process & process environment
2. Process Control
Process identifier, fork, exec…
3. Process relationship
4. Signal
5. Inter-process communication (IPC)
Pipe, FIFO
semaphore, shared memory, message queue
6. Daemon
7. Thread
1. Process & Process Environment
What is a process?
Program and process
Process: an address space with one or
more threads executing within that address
space, and the required system resources
for those threads. (SUSv3)
The startup of a process
System call “fork”
Process resources
struct task_struct
System space stack
…
System call “exec”
The entry of C programs
System stack
The entry of C programs
crt0.o
cc/ld
main function
function prototype:
int main(int argc, char *argv[]);
The termination of a process
Five ways of terminating a process
Normal termination
Return from “main” function
Call “exit” function
Call “_exit” function
Abnormal termination
Call “abort” function
Terminated by a signal
exit & _exit functions
Function prototype:
#include <stdlib.h>
void exit(int status);
#include <unistd.h>
void _exit(int status);
Exit status
Difference
_exit is corresponding to a system call,
while “exit” is a library function.
_exit terminate a process immediately.
Exit handler
atexit function
Register a function to be called at normal
program termination.
Prototype:
#include <stdlib.h>
int atexit(void (*function)(void));
on_exit function
Example
The memory map of a C program
Text segment (code segment)
Data segment
Initialized data
Uninitialized data
Heap
Stack
Command line arguments
main function
int main(int argc, char *argv[]);
Example:
The implementation of echo(1)
Command line option
Standard usage
getopt function
getopt function
Prototype:
int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
Question:
getopt(argc, argv, “if:lr”);
Program example (P104, in BLP)
Environment variables
Environment table
Environment pointer
extern char **environ;
putenv & getenv functions
Get, set or unset an environment
variable
#include <stdlib.h>
char *getenv(const char *name);
int putenv(char *string);
int setenv(const char *name, const char *value, int
overwirte);
void unsetenv(const char *name);
Shared object
Shared object
Dynamic link
Advantages and disadvantages
Example
How to create a static and shared library?
How to use (link) a static or shared library?
Memory allocation
Allocate and free dynamic memory.
#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nmemb, size_t size);
void free(void *ptr);
void realloc(void *ptr, size_t size);
2. Process control
Process identifier
System call “fork”
The simple synchronization between
parent and child process
The “exec” function family
Example:
The implementation of a simple shell
Process identifier
fork
fork: create a child process
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
returned value:
pid of child (in the current (parent) process),
0 (in child process),
-1 (failure)
A simple example
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
/* fork系统调用的第一个例子(不含错误检查)*/
void main()
{
printf(“Hello, world!\n”);
fork();
printf(“bye\n”);
}
The usage of “fork”
Code example
if ( (pid=fork()) < 0) {
/* error handling */
} else if (pid == 0) {
/* child */
} else {
/* parent */
};
Program example
Program8-1 in APUE
File sharing
所有由父进程打开的描述符都被复制到子进程
中。父、子进程每个相同的打开描述符共享一
个文件表项
vfork & clone functions
vfork
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
clone
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack,
int flag, void *arg);
The simple synchronization
between parent and child process
The relationship between parent and
child process
wait and waitpid functions
The relationship between parent
and child process
The parent terminates before the child
Orphan process
The child terminates before the parent
SIGCHLD signal
Handled by wait/waitpid in parent
Not handled by wait/wait in parent ->
zombie
wait & waitpid functions
Wait for process termination
Prototype
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
Example
Race condition
int main(void){
pid_t
pid;
}
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) {
charatatime("output cccccccccccc from child\n");
} else {
charatatime("output pppppppppp from parent\n");
}
exit(0);
An improvement
int main(void){
pid_t pid;
TELL_WAIT();
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) {
WAIT_PARENT();
/* parent goes first */
charatatime("output cccccccccccc from child\n");
} else {
charatatime("output pppppppppp from parent\n");
TELL_CHILD(pid);
}
exit(0);
}
The “exec” family of functions
Replace the current process image with a
new process image.
执行新程序的进程保持原进程的一系列特征:
pid, ppid, uid, gid, working directory, root
directory …
euid/egid?
打开文件描述符?
Functions prototypes
#include <unistd.h>
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[]);
#include <unistd.h>
int execve(const char *filename, char * const argv[],
char * const envp[]);
exec and opened file descriptor
close-on-exec bit of a file descriptor
Set by “fcntl” function
fcntl(fd, F_SETFD, 0); /*系统默认, 打开文件
描述符在 exec 时不关闭 */
fcntl(fd, F_SETFD, 1); /*打开文件描述符在
exec 时关闭 */
Using fork and exec together
Two ways of using fork
The parent process duplicates itself, and then two
different pieces of codes are executed in parent
process and child process.
A process want to execute another program.
Example:
The implementation of “system” function
int system(const char*cmdstring);
Example: a simple shell
printf("%% "); /* print prompt */
while (fgets(buf, MAXLINE, stdin) != NULL) {
buf[strlen(buf) - 1] = 0;
/* replace newline with null */
if ( (pid = fork()) < 0 )
err_sys(“fork error”);
else if ( pid == 0 ) {
/* child */
execlp(buf, buf, (char *) 0);
fprintf(stderr, "couldn't execute: %s", buf);
exit(127);
}
if ( (pid = waitpid(pid, &status, 0)) < 0 ) /* parent */
err_sys(“waitpid error”);
printf("%% ");
}
3. Process relationship
父进程和子进程
进程树
ps, pstree命令
Startup & login (1)
Login on serial terminal
Startup & login (2)
Network login
Process group & session
Process group
Session
The set of one or more process(es).
getpgrp/setpgid functions
The set of one or more process group(s).
setsid function
Controlling terminal
Why are they introduced?
Job control
Process group & session (cont’d)
Process group & session (cont’d)
4. Signal
The concept of signals
The “signal” function
Send a signal
kill, raise
The “alarm” and “pause” functions
Reliable signal mechanism
The concept of signals
Signal
Software interrupt
Mechanism for handling asynchronous events
Having a name (beginning with SIG)
Defined as a positive integer (in <signal.h>)
How to produce a signal
按终端键,硬件异常,kill(2)函数,kill(1)命令,软
件条件,...
Signals in Linux/UNIX
名称
说明
SIGABRT
进程异常终止(调用abort函数产生此信号)
SIGALRM
超时(alarm)
SIGFPE
算术运算异常(除以0,浮点溢出等)
SIGHUP
连接断开
SIGILL
非法硬件指令
SIGINT
终端终端符(Clt-C)
SIGKILL
终止(不能被捕捉或忽略)
SIGPIPE
向没有读进程的管道写数据
SIGQUIT
终端退出符(Clt-\)
SIGTERM
终止(由kill命令发出的系统默认终止信号)
SIGUSR1
用户定义信号
SIGUSR2
用户定义信号
Signals in Linux/UNIX (cont’d)
名称
说明
SIGSEGV
无效存储访问(段违例)
SIGCHLD
子进程停止或退出
SIGCONT
使暂停进程继续
SIGSTOP
停止(不能被捕捉或忽略)
SIGTSTP
终端挂起符(Clt-Z)
SIGTTIN
后台进程请求从控制终端读
SIGTTOUT
后台进程请求向控制终端写
Signal handling
忽略信号
不能忽略的信号:
SIGKILL, SIGSTOP
一些硬件异常信号
执行系统默认动作
捕捉信号
The “signal” function
Installs a new signal handler for the signal
with number signum.
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
(Returned Value: the previous handler if success, SIG_ERR if
error)
The “handler” parameter
a user specified function, or
SIG_DEF, or
SIG_IGN
The ”signal” function (cont’d)
Program example
static void sig_usr(int);
int main(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
err_sys("can't catch SIGUSR1");
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
err_sys("can't catch SIGUSR2");
for ( ; ; )
pause();
}
Send a signal
kill(2): send signal to a process
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
(Returned Value: 0 if success, -1 if failure)
raise(3): send a signal to the current process
#include <signal.h>
int raise(int sig);
(Returned Value: 0 if success, -1 if failure)
alarm & pause functions
alarm: set an alarm clock for delivery of a signal
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
(Returned value: 0, or the number of seconds remaining of
previous alarm)
pause: wait for a signal
#include <unistd.h>
int pause(void);
(Returned value: -1, errno is set to be EINTR)
alarm & pause functions (cont’d)
Program example
The implementation of the “sleep” function
unsigned int sleep1(unsigned int nsecs)
{
if ( signal(SIGALRM, sig_alrm) == SIG_ERR)
return(nsecs);
alarm(nsecs);
/* start the timer */
pause();
/*next caught signal wakes us up*/
return(alarm(0) ); /*turn off timer, return unslept time */
}
Possible problems
Problems related to time
Race condition
Interrupted system calls
Reentrancy
Reliable signal mechanism
Weakness of the signal function
Signal block
Signal set
signal mask
sigset_t data type
Signal handling functions using signal set
sigprocmask, sigaction, sigpending, sigsuspend
signal set operations
#include <signal.h>
int
int
int
int
sigemptyset(sigset_t *set);
sigfillset(sigset_t *set);
sigaddset(sigset_t *set, int signum);
sigdelset(sigset_t *set, int signum);
(Return value: 0 if success, -1 if error)
int sigismember(const sigset_t *set, int signum);
(Return value: 1 if true, 0 if false)
sigprocmask function
检测或更改(或两者)进程的信号掩码
#include <signal.h>
sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
(Return Value: 0 is success, -1 if failure)
参数“how”决定对信号掩码的操作
SIG_BLOCK: 将set中的信号添加到信号掩码(并集)
SIG_UNBLOCK: 从信号掩码中去掉set中的信号(差集)
SIG_SETMASK: 把信号掩码设置为set中的信号
例外: SIGKILL, SIGSTOP
sigpending function
返回当前未决的信号集
#include <signal.h>
sigpending(sigset_t *set);
(Returned Value: 0 is success, -1 if failure)
Example:
critical.c (Prog10-11 in APUE)
sigaction function
检查或修改(或两者)与指定信号关联的处理动作
#include <signal.h>
sigaction(int signum, const struct sigaction *act, struct
sigaction *oldact);
(Returned Value: 0 is success, -1 if failure)
struct sigaction至少包含以下成员:
handler_t sa_handler; /* addr of signal handler, or SIG_IGN,
or SIG_DEL */
sigset_t sa_mask; /* additional signals to block */
int sa_flags;
/* signal options */
sigsuspend function
用sigmask临时替换信号掩码,在捕捉一个信号或发生
终止该进程的信号前,进程挂起。
#include <signal.h>
sigsuspend(const sigset *sigmask);
(Returned value: -1, errno is set to be EINTR)
sigsuspend和pause
signal function review
用sigaction实现signal函数
Sigfunc * signal(int signo, handler_t func) {
struct sigaction
act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef
SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
} else {
#ifdef
SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}
/* SunOS */
/* SVR4, 44BSD */
Example:
solution of race condition
int main(void){
pid_t pid;
TELL_WAIT();
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) {
WAIT_PARENT();
/* parent goes first */
charatatime("output cccccccccccc from child\n");
} else {
charatatime("output pppppppppp from parent\n");
TELL_CHILD(pid);
}
exit(0);
}
static sigset_t
newmask, oldmask, zeromask;
static void sig_usr(int signo) {/* one handler for SIGUSR1, SIGUSR2 */
sigflag = 1; return;
}
void TELL_WAIT() {
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
err_sys("signal(SIGINT) error");
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
err_sys("signal(SIGQUIT) error");
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGUSR1);
sigaddset(&newmask, SIGUSR2);
/* block SIGUSR1 and SIGUSR2, and save current signal mask */
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys("SIG_BLOCK error");
}
void WAIT_PARENT(void) {
while (sigflag == 0)
sigsuspend(&zeromask);
}
/* and wait for parent */
sigflag = 0;
/* reset signal mask to original value */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("SIG_SETMASK error");
void TELL_CHILD(pid_t pid) {
kill(pid, SIGUSR1);
}
/* tell child we're done */
5. Inter-process communication
IPC: Inter-Process Communication
IPC mechanisms
shared file
signal
pipe, FIFO (named pipe), message queue,
semaphore, shared memory
socket
IPC illustrations
Simple Client-Server or IPC model
The concept of pipe
Pipe
Pipe mechanism in a shell
e.g. cmd1 | cmd2
Pipe is half-duplex
管道只能在共同祖先的进程间使用
管道也是文件
命名管道(FIFO)
The pipe function
The pipe function: create a pipe
#include <unistd.h>
int pipe(int filedes[2]);
(Returned value: 0 if success, -1 if failure)
A pipe: First In, First Out
filedes[0]:read, filedes[1]: write
A pipe in a single process
A pipe between the parent & child
The coordination
of pipe read & write
写管道时,常数PIPE_BUF规定了内核中
管道缓存器的大小
管道的一端关闭时,
写端关闭,读该管道在所有数据都被读取后,
read返回0,表示达到了文件结束
读端关闭,写该管道产生信号SIGPIPE
Examples
pipe1.c
管道用于标准输入和标准输出
管道:shell中的形式
cmd1 | cmd2
重定向 cmd > file
实现代码
执行cmd1前
if (fd[1] != STDOUT_FILENO) {
if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys(“dup2 error to stdout);
}
执行cmd2前
if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
err_sys(“dup2 error to stdin);
}
Examples
pipe2.c
pipe Application(1):
solution of race condition
int main(void){
pid_t pid;
TELL_WAIT();
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) {
WAIT_PARENT();
/* parent goes first */
charatatime("output cccccccccccc from child\n");
} else {
charatatime("output pppppppppp from parent\n");
TELL_CHILD(pid);
}
exit(0);
}
static int pfd[2];
void TELL_WAIT() {
if (pipe(pfd) < 0)
err_sys("pipe error");
}
void WAIT_PARENT(void) {
char c;
if (read(pfd[0], &c, 1) != 1)
err_sys("read error");
if (c != 'p')
err_quit("WAIT_PARENT: incorrect data");
}
void TELL_CHILD(pid_t pid) {
if (write(pfd[1], "p", 1) != 1)
err_sys("write error");
}
pipe Application(2): shell
shpipe.c
popen & pclose functions
popen, pclose: process I/O
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
Applications of popen & pclose
按页输出
在程序中获得另一个程序的输出
Home work: popen的实现
用pipe, fork实现popen
FIFO: named pipe
管道和命名管道
相同点
不同点
文件系统中
同步:一个重要的考虑
mkfifo(1), mkfifo(3), mknod(1), mknod(2)
创建FIFO
mkfifo: make a FIFO special file (a named
pipe)
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
(Returned value: 0 if success, -1 if failure)
Examples
fifo1.c (Ch12 in BLP)
list a fifo (ls –lF)
用open打开一个FIFO
Review: “open” system call
int open(const char *pathname, int flags);
“flags” parameter
必须指定的互斥模式:
O_RDONLY, O_WRONLY, O_RDWR
O_NONBLOCK
consideration:
读端/写端
同步
FIFO的同步和读写
打开FIFO时的同步
一般情况下(没有说明O_NONBLOCK),只读打开
要阻塞到某个其它进程为写打开此FIFO;类似的,
为写打开一个FIFO要阻塞到某个其它进程为读而打
开它。
如果指定了O_NONBLOCK,则只读打开立即返回;
只写打开也立即返回,但如果没有进程已经为读而
打开此FIFO,那么open将出错返回 -1,errno置为
ENXIO。
读写FIFO时的同步
same as pipe
同步示例
shell中使用fifo的例子
cat < my_fifo
echo “a string to fifo” > my_fifo
fifo2.c (Ch12 in BLP)
FIFO的应用(1)
用FIFO复制输出流
例
FIFO的应用(2)
C/S应用程序
例:client.c, server.c
System V IPC
IPC objects
信号量(semaphore set)
消息队列(message queue)
共享内存(shared memory)
shell命令
ipcs, ipcrm
System V IPC的共同特征
标识符与关键字
引用IPC对象:标识符
创建IPC对象时指定关键字(key_t key;)
key的选择;预定义常数IPC_PRIVATE;ftok函数
内核将关键字转换成标识符
许可权结构
和文件类比
struct ipc_perm
SV IPC System Calls Overview
功能
消息队列
信号量
共享内存
分配一个IPC对象,获得对IPC
的访问
msgget
semget
shmget
IPC操作: 发送/接收消息,信号 msgsnd/
量操作,连接/释放共享内存
msgrcv
semop
shmat/
shmdt
IPC控制:获得/修改状态信息, msgctl
取消IPC
semctl
shmctl
Semaphore
并发程序设计
互斥和同步
PV操作(原语)
PV操作和信号量
procedure p(var s:samephore){
s.value=s.value-1;
if (s.value<0) asleep(s.queue);
}
procedure v(var s:samephore){
s.value=s.value+1;
if (s.value<=0) wakeup(s.queue);
}
Linux/UNIX的信号量机制
semaphore set
struct semid_ds
struct ipc_perm sem_perm;
struct sem *sem_base; /* ptr to first sem in set */
time_t sem_otime; /* last operation time */
time_t sem_ctime; /* last change time */
ushort sem_nsems; /* count of sems in set */
semaphore set system calls
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
int semop(int semid, struct sembuf *sops, unsigned nsops);
int semctl(int semid, int semnum, int cmd, ...);
semget: get a semaphore set
identifier
prototype
int semget(key_t key, int nsems, int semflg);
“key” parameter
“semflg” parameter
预定义常数IPC_PRIVATE;
约定的关键字
ftok函数
设置访问权限(低9位)
IPC_CREAT, IPC_EXCL 按位或
examples
sem1.c
semop: semaphore operations
prototype
int semop(int semid, struct sembuf *sops, unsigned nsops);
“sops” parameter
struct sembuf {
unsigned short int sem_num; /* semaphore number */
short int sem_op;
/* semaphore operation */
short int sem_flg;
/* operation flag */
}
examples:
PV操作的实现
semctl: semaphore control
operations
prototype
int semctl(int semid, int semnum, int cmd, ...);
the 4th argument
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
“cmd” parameter
semctl: semaphore control
operations (cont’d)
“cmd” parameter
IPC_STAT: 对指定的信号量标识返回arg.semid_ds
结构中的当前值
IPC_SET: 在进程有足够权限的前提下,把信号量集
合的当前关联值置为arg.semid_ds结构给出的值
IPC_RMID: 删除信号量集合
SETVAL: 设置信号量集合中由semnum指定的单个
信号量的值(设为arg.val)
examples
set_semvalue(初始化), del_semvalue(结束)
Examples
一个完整的实例
sem1.c(进程互斥)
Home work:
用程序模拟实现生产者/消费者问题
进程同步
Message queue
消息队列
消息队列是消息的链表,存放在内核中并由
消息队列标识符标识。
First in, first out
message type: 优先级
块数据
struct msqid_ds
message queue system calls
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int
int
int
int
msgget(key_t key, int size, int flag);
msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
msgctl(int msqid, int cmd, struct shmid_ds *buf);
msgctl: message control
operations
prototype
int msgctl(int msqid, int cmd, struct shmid_ds *buf);
“cmd” parameter
IPC_STAT: 把msqid_ds结构中的数据置为消息队列
的当前关联值
IPC_SET: 在进程有足够权限的前提下,把消息队列
的当前关联值置为msqid_ds结构给出的值
IPC_RMID: 删除消息队列
Example
A C/S application
One server, several clients: only one queue
is required.
Compared with FIFO implementation
Shared memory
共享内存
共享内存是内核为进程创建的一个特殊内存
段,它可连接(attach)到自己的地址空间,
也可以连接到其它进程的地址空间
最快的进程间通信方式
不提供任何同步功能
shared memory system calls
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int semget(key_t key, int size, int flag);
void *shmat(int shmid, void *addr, int flag);
int shmdt(void *addr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
mmap/munmap system calls
mmap/munmap: map or unmap files or
devices into memory
6. Daemon process
什么是daemon进程
daemon进程的实现方法
编程规则
出错记录
What is a daemon?
What is a daemon? (cont’d)
daemon
精灵进程或守护进程
后台执行, 没有控制终端或登录 Shell 的进
程
why daemon?
Concepts related to job control
Process group & session
Controlling terminal
jobs, fg, bg comands
SIGINT, SIGQUIT, SIGTSTP, SIGHUP
signals
A solution the problem
nohup command & >> logfile
daemon进程的实现(1)
编程规则
首先调用fork,然后使父进程exit
调用setsid创建一个新的会话期
将当前工作目录更改为特定目录
进程的umask设为0
关闭不需要的文件描述符
Example
int daemon_init(void) {
pid_tpid;
if ( (pid = fork()) < 0)
return(-1);
else if (pid != 0)
exit(0); /* parent goes bye-bye */
/* child continues */
setsid();
/* become session leader */
chdir("/");
/* change working directory */
umask(0);
/* clear our file mode creation mask */
}
return(0);
daemon进程的实现(2)
出错记录
7. Threads
What is a thread
Basic pthread functions
Thread synchronization
Thread attributes
Thread cancellation
What is a thread?
Thread:
A single flow of control within a process. (susv3)
Process and thread
New process: when a process executes a fork call, a
new copy of the process is created with its own
variables and its own PID.
New thread: When we create a new thread in a process,
the new thread of execution gets its own stack (and
hence local variables) but shares global variables, file
descriptors, signal handlers, and its current directory
state with the process that created it.
Process and thread
POSIX thread
POSIX1003.1c
pthread library
pthread.h header file
/usr/lib/libpthread.so, /usr/lib/libpthread.a
/usr/include/pthread.h
Compiler options
gcc thread.c –o thread -lpthread
Basic thread functions(1)
Create a new thread
#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
Terminate the calling thread
void pthread_exit(void *retval);
Basic thread functions(2)
Wait for termination of another thread
#include <pthread.h>
int pthread_join(pthread_t th, void **thread_return);
Put a running thread in the detached state
int pthread_detach(pthread_t th);
Thread synchronization
用信号量进行同步
用互斥量进行同步
用条件变量进行同步
POSIX4 semaphore
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int
value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_destroy(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_getvalue(sem_t *sem, int *sval);
Example
Producer-consumer problem
thread4.c, thread4a.c (in Ch11, BLP)
Mutex (Mutual Exclusion)
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const
pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
Example
thread5.c
Thread attributes
线程属性对象
pthread_attr_t
初始化
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
get/set族函数
Get/Set thread attributes
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int
detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int
*detachstate);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int
*policy);
int pthread_attr_setschedparam(pthread_attr_t *attr, int
param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, int
*param);
Example(1): 线程属性-分离线程
detachstate属性
Values:
PTHREAD_CREATE_JOIN /
PTHREAD_CREATE_DETACHED
thread6.c
Example(2): 线程属性-调度
schedpolicy属性
调度策略
Values:
schedparam属性
SCHED_OTHER/SCHED_RR/SCHED_FIFO
调度参数,主要是优先级
thread7a.c
Thread cancellation
#include <pthread.h>
int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
Multithread program
Examples:
thread9.c, thread9a.c (in BLP)
Review