D4.14
1、信号的产生:①一个进程向另一进程发送信号;②内核发送信号;③底层硬件发送信号。
2、kill 进程号 -s sig选项,例:kill 3973 -s SIGKILL 使3973进程终止。
注:(1)进程号查询,例:ps –axf | grep demo (其中,demo是正在执行的可执行文件)。
(2)在while(1)死循环中,ctrl + C 等价于sig选项的SIGINT(终止进程)。
1、kill(信号发送)
1、头文件:#include <sys/types.h> #include
<signal.h>
2、函数原型:int kill(pid_t pid, int sig);
3、函数形参:pid_t pid:将要被发送信号的进程的进程号;
sig:信号选项。
注:若将pid_t pid置为-1,则向当前所有进程发送指定的sig信号。
4、函数返回值:成功返回0,失败返回-1,errno被设置。
2、signal(设置信号处理方式)
1、头文件: #include <signal.h>
2、函数原型: sighandler_t
signal(int signum, sighandler_t handler);
3、函数形参: signum:信号编号(选项);
handler:信号处理方式(具体三种方式见下)。
注:信号处理方式:(1)忽略:SIG_IGN;(2)默认:SIG_DFL;
(3)捕获:填写类型为void (*)(int型形参)的捕获函数的地址。
4、函数返回值:成功返回上一次的处理方式,失败返回SIG_ERR宏值,errno被设置。
5、使用示例:将ctrl + C信号(原为SIGINT–终止进程)变为调用print函数。
二十五、pthread_create(线程创建)
1、头文件:#include<pthread.h>
2、函数原型:
int pthread_create(pthread_t *thread, const
pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
3、函数形参:thread:存放线程的TID(由pthread_t定义)地址;
attr:设置线程属性,一般置NULL;
start_routine:线程所要执行的函数地址;
arg:传递给线程函数的参数。
注:(1)start_routine是void *型函数,其形参也为void *型。
(2)arg:这个参数会传递给pth_arg,如果参数很多的话,可做成一个结构体,然后将结构体变量的地址传过去。若不想传递参数,可设置为NULL。
4、函数返回值:成功返回0,失败返回错误号。
5、使用示例:
注:编译时要链接线程库(libpthread.a/.so):gcc
pthread create.c –lpthread
(1)arg为NULL。
(2)arg有值且为全局变量,实现所有线程共享主线程(进程)的数据段。
(3)arg有值且为局部变量,使用地址传参,在调用的函数中必须将void
*arg强转为对应的数据类型。
二十六、pthread_join(线程等待)
1、头文件:#include<pthread.h>
2、函数原型:int
pthread_join(pthread_t thread, void **retval);
3、函数形参: thread:指定要回收的次线程的TID;
retval:次线程函数返回的返回值。
4、函数返回值:成功返回0,失败返回错误号。
5、功能:阻塞等待TID为thread的次线程结束,结束时该函数回收次线程所占用资源。
注:该函数只对次线程有意义,对主线程没有意义,因为主线程结束时整个进程就结束了,而整个进程资源会由父进程回收。
6、等待线程的目的:
(1)保证线程的退出顺序:保证一个线程退出并且回收资源后允许下一个进程退出。
(2)回收线程退出时的资源情况:保证当前线程退出后,创建的新线程不会复用刚才退出线程的地址空间。
(3)获得新线程退出时的结果是否正确的退出返回值,这个有点类似回收僵尸进程的wait,保证不会发生内存泄露等问题。
7、使用示例:result接TID为id、id2的线程退出时的返回值。
注:result在该函数中形参使用需为void *型,而在printf时需要强转为字符串类型。
二十七、pthread_cancel/exit(线程退出)
1、头文件:#include<pthread.h>
2、函数原型:
被动退出:int pthread_cancel(pthread_t thread);
主动退出:void pthread_exit(void *retval); //或使用return直接返回
注:pthread_exit类似于exit函数,不过exit是终止整个进程的,而pthread_exit是终止次线程的。如果在次线程里面调用错误,调用的是exit,整个进程就终止了。
3、函数形参: thread:指定要取消的线程的TID;
retval:线程结束时的返回值。
注:对于retval,如果返回值很多时,就封装成一个结构体,返回结构体变量的地址即可。
4、函数返回值:成功返回0,失败返回非零错误号。
5、使用示例:
(1)被动退出·pthread_cancel
(2)主动退出·pthread_exit,使用result接返回值, 会打印出mythread2 exit!
(3)主动退出·return,使用result接返回值,会打印出mythread1 exit!
二十八、mutex线程互斥锁
1、pthread_mutex_init初始化互斥锁
1、头文件:#include<pthread.h>
2、函数原型:
int
pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t
*restrict attr);
3、函数形参: mutex:互斥锁地址(需自定义,如:pthread_mutex_t mutex;);
attr:互斥锁的属性(一般设置为NULL表示使用默认属性)。
注:(1)pthread_mutex_t是一个结构体类型,所以mutex实际上是一个结构体变量。
(2)attr也可设置一些互斥锁的特殊功能。
4、函数返回值:总是返回0,所以这个函数不需要进行出错处理。
5、注意事项:互斥锁尽量作为全局变量
2、pthread_mutex_(try/un)lock加锁/解锁操作
1、pthread_mutex_lock(&mutex)(阻塞加锁)访问临界区加锁操作。
2、pthread_mutex_trylock(
&mutex)(非阻塞加锁),通常不使用。
注:与pthread_mutex_lock()类似,不同:锁已经被占据时返回 EBUSY 而不是挂起等待。
3、pthread_mutex_unlock(&mutex):
访问临界区解锁操。
注:mutex:互斥锁的地址。
3、pthread_mutex_destroy销毁互斥锁
1、头文件:#include<pthread.h>
2、函数原型:int pthread_mutex_destroy(pthread_mutex_t
*mutex);
3、函数形参: mutex:互斥锁地址。
4、函数返回值:成功返回0,失败返回非零错误号。
5、功能:销毁,即删除互斥锁相关的数据,释放互斥锁数据所占用的各种内存资源。
4、条件变量的使用
条件变量的使用步骤:
(1)定义一个条件变量(全局变量),pthread_cond_t;
注:由于条件变量需要互斥锁的配合,所以还需要定义一个线程互斥锁。
(2)初始化条件变量;
(3)使用条件变量;
(4)删除条件变量,也需要把互斥锁删除。
1、pthread_cond_init初始化条件变量
1、头文件:#include<pthread.h>
2、函数原型:
int
pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t
*restrict attr);
3、函数形参:cond:条件变量;
attr:用于设置条件变量的属性,设置为NULL,表示使用默认属性。
4、函数返回值:成功返回0,失败返回非零错误号。
5、补充:也可以直接初始化:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//与互斥锁的初始化的原理一样
6、使用示例:
pthread_cond_t
cond; //定义条件变量
pthread_cond_init(&cond,
NULL); //第二个参数为NULL,表示不设置条件变量的属性
2、pthread_cond_wait等待条件
1、头文件:#include<pthread.h>
2、函数原型:
int
pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict
mutex);
3、函数形参:cond:条件变量;
mutex:和条件变量配合使用的互斥锁。
4、函数返回值:成功返回0,失败返回非零错误号。
3、pthread_cond_signal设置条件变量
1、头文件:#include<pthread.h>
2、函数原型:int
pthread_cond_signal(pthread_cond_t *cond);
3、函数形参:cond:条件变量。
4、函数返回值:成功返回0,失败返回非零错误号。
5、功能:
调用pthread_cond_signal去设置条件变量,相当是给pthread_cond_wait发送了一个线程间专用的信号,通知调用pthread_cond_wait的线程,某某条件满足了,不要再睡了,赶紧做事吧。
6、补充:
当调用pthread_cond_wait函数等待条件满足的线程只有一个时,就是用pthread_cond_signal来唤醒,如果说有多个线程都调用pthread_cond_wait在等待时,使用int pthread_cond_broadcast(pthread_cond_t *cond);
注:pthread_cond_broadcast可以将所有调用pthread_cond_wait而休眠的线程都唤醒。
4、删除条件变量
1、头文件:#include<pthread.h>
2、函数原型:int pthread_cond_destroy(pthread_cond_t
*cond);
3、函数形参:cond:条件变量。
4、函数返回值:成功返回0,失败返回非零错误号。
二十九、sem线程信号量
线程信号量使用步骤:
(1)定义信号量集合(如:sem_t sem[3]);
注:线程信号量集合其实就是一个数组,数组每个元素就是一个信号量。
(2)初始化集合中的每个信号量;
(3)p、v操作;
(4)进程结束时,删除线程信号量集合。
1、sem_init初始化信号量
1、头文件:#include
<semaphore.h>
2、函数原型:int sem_init(sem_t
*sem, int pshared, unsigned int value);
3、函数形参:sem:信号量集合中的某个信号量地址;
pshared:若为0:给线程使用 / 若为非0:可以给进程使用;
value:初始化值。
注:pshared:通常不用!0值。对于进程来说,更多的还是使用进程信号量,因为线程信号量用到进程上时,存在一些不稳定的情况。
4、函数返回值:成功返回0,失败返回-1,errno被设置。
2、sem_wait信号量操作
1、P操作
(1)头文件:#include <semaphore.h>
(2)函数原型:int sem_wait(sem_t *sem);//阻塞p操作
(3)函数形参:sem:信号量集合中的某个信号量地址;
(4)函数返回值:成功返回0,失败返回-1,errno被设置。
(5)功能:阻塞p操作集合中某个信号量,信号量的值-1。
如果能够p操作成功最好,否则就阻塞直到p操作操作成功为止。
(6)使用示例:sem_wait(&sem[0]);
2、V操作
(1)头文件:#include <semaphore.h>
(2)函数原型:int sem_post(sem_t *sem);
(3)函数形参:sem:信号量集合中的某个信号量地址;
(4)函数返回值:成功返回0,失败返回-1,errno被设置。
(5)功能:v操作成功后,信号量的值+1。
对某个信号量进行v操作,v操作不存在阻塞问题。
(6)使用示例:sem_post(&sem[0]);
D4.15
网络编程