📄 2.html
字号:
SIGTRAP5 从陷阱中回朔 否<br>
SIGABRT6 异常终止信号 是<br>
SIGEMT 7 EMT指令 否<br>
SIGFPE 8 不正确的算术操作信号 是<br>
SIGKILL9 终止信号 是<br>
SIGBUS 10 总线错误 否<br>
SIGSEGV 11检测到非法的内存调用 是<br>
SIGSYS 12 系统call的错误参数 否<br>
SIGPIPE 13在无读者的管道上写 是<br>
SIGALRM 14 报时信号 是<br>
SIGTERM 15终止信号 是<br>
SIGURG 16 IO信道紧急信号 否<br>
SIGSTOP 17暂停信号 是<br>
SIGTSTP 18 交互暂停信号 是<br>
SIGCONT 19如果暂停则继续 是<br>
SIGCHLD 20 子线程终止或暂停 是<br>
SIGTTIN 21后台线程组一成员试图从控制终端上读出 是<br>
SIGTTOU 22 后台线程组的成员试图写到控制终端上 是<br>
SIGIO 23允许I/O信号 否<br>
SIGXCPU 24 超出CPU时限 否<br>
SIGXFSZ25 超出文件大小限制 否<br>
SIGVTALRM 26 虚时间警报器 否<br>
SIGPROF27 侧面时间警报器 否<br>
SIGWINCH 28 窗口大小的更改 否<br>
SIGINFO29 消息请求 否<br>
SIGUSR1 30 保留作为用户自定义的信号1 是<br>
SIGUSR2 31 保留作为用户自定义的信号 是<p>
请求按默认的规则进行信号处理<br>
SIG_DFL (void (*)(int))0<br>
请求忽略信号<br>
SIG_IGN (void (*)(int)) 1<br>
注意:信号队列中最多允许有64个信号<p>
<br>
3.2 pthreads/pthread_ipc.c<p>
此源码文件包括了一套完整的消息队列型线程通信机制,消息队列是线程通信的主要手段,通过阅读下面的函数分析,将使读者了解OSKit到底是用什么函数来具体实现信号队列,从而进行线程通信的。<p>
3.2.1消息发送:<br>
说明:当一个线程要向另一个线程发送消息的时候,OSKit使用下面定义的函数来实现一个线程向另一个线程传递消息。<br>
oskit_error_toskit_ipc_send ( pthread_t dst,void *msg,<br>
oskit_size_t msg_size,oskit_s32_t timeout)<br>
dst:目标地址 *msg:指向消息的指针<br>
msg_size:消息大小(32位无符号整形) timeout:超时<p>
3.2.2send的算法<br>
发送一个同步消息,直到接收者发送终止消息或超时才结束<br>
为避免死锁,给没个人加一个锁,并关中断。<br>
assert_interrupts_enabled();<br>
disable_interrupts( );<br>
pthread_lock(target->waitlock);<br>
通过条件,检测目标线程是否在等待接受:<br>
条件: a:目标线程的等待标志 THREAD_WS_IPCRECV_WAIT(线程接收等待位)<br>
b:目标线程号存在<br>
c:目标线程等于任意一个线程<br>
d:消息大小不为0<br>
条件成立: a ( b || c) d== 1 才可以发送<br>
if (target->waitflags THREAD_WS_IPCRECV_WAIT<br>
(target->ipc_state.tid ==pthread->tid||target->ipc_state.tid== ANYTID))<br>
{ if(msg_size)<br>
{Memcpy(target->ipc_state.msg,<br>
msg,MIN(msg_size,target->ipc_state.msg_size));<br>
if(msg_size > target->ipc_state.msg_size)<br>
err =OSKIT_ERANGE;<br>
}<br>
}<br>
把数据的大小和发送者的ID告诉接受线程:<br>
target->ipc_state.msg_size= msg_size;<br>
target->ipc_state.tid =pthread->tid;<br>
清除接受位:<br>
target->waitflags =~THREAD_WS_IPCRECV_WAIT;<br>
pthread_unlock ( target->waitlock);<br>
注意: flagA = ~flagB实际上就是将flagB中等于1的位在flagB中清0<br>
发送队列:<br>
queue_enter (target->ipc_state.senders,pthread,pthread_thread_t*,<br>
ipc_state.senders_chain)<br>
target->ipc_state.senders:发送线程的IDpthread:<br>
pthread_thread_t*:指向消息的指针是pthread_thread_t类型<br>
ipc_state.senders_chain:发送队列的指针<br>
队列间参数传递:<br>
pthread->ipc_state.msg= msg; /* 消息 */<br>
pthread->ipc_state.msg_size = msg_size; /* 消息的长度*/<br>
pthread->ipc_state.tid = dst; /* 消息的目的地址 */<br>
pthread->waitflags =THREAD_WS_IPCSEND_WAIT;<br>
/* 消息目的等待位置1 */<p>
3.2.3消息接收<br>
说明:当一个线程要从其消息队列中开始接受消息的时候,OSKit提供了下面的函数供线程调用。<br>
oskit_error_toskit_ipc_recv ( pthread_t src,void *msg,<br>
oskit_size_t msg_size,oskit_size_t *actual,oskit_s32_t timeout )<br>
src: 发送线程的ID *msg: 指向消息的指针<br>
msg_size: 消息大小(32位无符号整形)<br>
actual: 实际消息的大小 timeout: 超时<p>
3.2.4receive的算法<br>
等待从发送线程来的消息<br>
通过条件,检测是否接受消息<br>
a:有等待发送的线程<br>
b:线程等待位THREAD_WS_IPCSEND_WAIT(发送等待标志)<br>
c:发送线程存在<br>
条件成立:a(b||c)<br>
pthread_lock(source->waitlock);<br>
if(source->waitflags THREAD_WS_IPCSEND_WAIT<br>
source->ipc_state.tid == pthread->tid){<br>
*actual = MIN(msg_size, source->ipc_state.msg_size);<br>
if(*actual) {<br>
memcpy(msg, source->ipc_state.msg,*act0ual);<br>
if (source->ipc_state.msg_size >msg_size)<br>
err =OSKIT_ERANGE;<br>
}<br>
}<br>
如果没有等待发送的进程,则让接受进程等待<br>
当发送队列为空且timeout=0时解锁,如果发送了但没接受,则重新初始化发送进程,重新发送。<p>
<br>
3.3 pthreads/pthread_signal.c<p>
此源码文件包括了一套完整的信号量型线程通信机制,信号量是线程通信的另一个重要的手段,通过阅读下面的函数分析,将使读者了解OSKit到底是用什么函数来具体实现信号量,从而进行线程通信的。<p>
3.3.1检测并更改阻塞的信号<br>
说明:当一个信号被发送出来的时候,并不一定马上能得到相应,一般来说,它要被阻塞一段时间,但系统也是就不管这些阻塞信号了,系统会定时执行此线程,用以检测阻塞的到底是什么信号,它的含义是什么,然后根据需求作出决定,可以将信号阻塞或者响应。<br>
intpthread_sigmask ( int how, const sigset_t *set, sigset_t *oset )<br>
how:SIG_BLOCK SIG_UNBLOCK SIG_SETMASK<br>
set:如果是空指针,则指向下一个信号<br>
oset:如果是空指针,则指向上一个信号记录<p>
3.3.2杀线程信号<br>
说明:OSKit以及所有的操作系统,都包含这个函数,因为它是操作系统所必须具备的基本功能,也就是说,当一个线程出于无响应状态很长时间,或者因为其他的什么原因线程不能得到执行,则调用它,将该线程杀死。<br>
intpthread_kill(pthread_t tid, int signo)<p>
3.3.3关线程锁<br>
说明:当线程接受到了消息后的响应过程中,有些时候是不希望被其他的线程打断的,所以OSKit提供了此函数调用,用来将线程锁起来,也可以理解为将线程保护了起来。<br>
intpthread_kill_locked ( pthread_thread_t *pthread, int signo )<p>
3.3.4在目标线程的信号等待队列中加一个信号<br>
说明:在信号发送和接受的过程中,线程间通讯并不一定是同步的,此时,OSKit提供了一个消息等待队列,将不能及时得到响应的消息用指针链接成为一个类似与链表的数据结构。当接受线程要响应信号的时候可以直接从消息队列里提取,这样作既可以提高通信效率,有可以增加通信的稳定性。<br>
intsigaddset ( pthread->sigpending, signo )<p>
3.3.5信号完成的动作<br>
说明:在用信号方式通信的时候,线程间传递的信号并不是要做的动作,而是动作的代码,而什么信号对应什么动作,还要有此汉说来进行解析,这样作是为了规范线程间通信,同时还可以节约空间,节省发送和接受的时间,从而大大提高系统的效率。<br>
intsigaction ( int sig, const struct sigaction *act, struct sigaction *oact)<br>
sig:指定信号 act:指向与指定信号向联系的规定信号动作的结构<br>
oact:指向存储先前与该信号相联系的动作的结构<p>
3.3.6测试或改变(或两者兼有)主调进程的信号掩码<br>
说明:所谓掩码就是信号的屏蔽码,比如说,当一个信号被发送的时候,它被自动加载到接收线程的信号掩码中,如果此时又向该线程发送了同样的信号,则阻塞该信号,知道前一个信号响应完毕。<br>
OSKit采用下面的函数完成的对信息掩码的测试和改变。<br>
intsigprocmask ( int how, const sigset_t *set, sigset_t *oset )<br>
how:指明改变信号集的方式<br>
SIG_BLOCK: 结果是当前集与实参set所指向的信号集的联合<br>
SIG_UNBLOCK:结果集是当前集与实参set所指向的信号集的补集的交<br>
SIG_SETMASK: 结果集是实参set所指向的信号集<br>
set:指向要用来改变当前被阻塞的信号集 oset: 存储当前的掩码<p>
3.3.7杀线程<br>
说明:此函数和前面介绍过的杀线程信号并不完全一样,源线程是通过看是否有向目的线程发信号的权限,如果有的话就杀掉它<br>
intkill ( pid_t pid, int signo )<br>
pid: 目标线程 signo: 所要发的信号<p>
3.3.8等待信号的线程队列<br>
说明:由于线程间通信不一定同步的原因,调用此函数创建信号等待队列是十分有必要的。<br>
int sigqueue( pid_t pid, int signo, const union sigval value )<p>
3.3.9等待内部信号<br>
说明:OSKit将信号分为内部信号和外部信号,这是十分有意义的,因为很多情况下,它们的处理方式是不一样的,有的外部消息可以不加理睬,但一般来说,内部消息是一定要及时响应的,系统通过调用下面的函数实现了等待一个内部信号,一旦等到,马上响应。<br>
oskit_error_toskit_sigwait_internal ( const sigset_t *set,siginfo_t<br>
*info,constoskit_timespec_t *timeout )<br>
sigset_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -