Linux学习总结(七)

Linux学习总结(七)

多线程异步管理——信号

线程并没有自己完全独立的异步信号管理机制,因此需要依赖于所在的进程,每个线程仅仅只能管理自己私有的信号屏蔽集合。因此信号操作时具有一下操作

  • (1)每个线程可以向其他线程发送信号,pthread_kill()函数用来完成这一操作,接受者为对应的线程
  • (2)每个线程可以设置自己的信号屏蔽集合,而不影响同进程下的其他线程,但初值从创建线程中继承,创建时,如果原线程有任何未决信号并不被新线程继承。pthread_sigmask()函数用来完成这一操作,其类似于进程的sigprocmask()函数
  • (3)同进程下所有线程共享对某信号的处理方法,即收到某个信号后,执行相同的信号处理函数,虽然每个线程都可以调用signal或者sigaction设置针对某信号的处理方式,但仅最后一次设置的处理方式
  • (4)向某个进程中发送某个信号,如果该信号的操作是终止的,则整个进程下的所有进程都将终止
    线程信号管理

pthread_kill发送信号
pthread_kill函数用来在线程间发送信号

int pthread_kill(pthread_t _thread0d, int _signo)

该函数有两个参数,threadid是传送信号的目标线程,signo是要传送给线程的信号。pthreadKill()函数用于请求将信号传送给线程
如果signo为0,则检测该线程是否存在而不发送信号。成功完成后,pthread_kill()将返回0.否则就会返回一个错误编号,用于指明错误(未设置errno变量)
pthread_sigmask调用线程的信号掩码
pthread_sigmask函数用来检查(或更改)调用线程的信号掩码,其操作类似于第8章介绍的siprocmask()函数

int pthread_sigmask(int
_how, _const _sigset_t *_restrict_newmask, _sigset_t *_restrict _oldmask)

第一个参数how定义如何更改调用线程的信号掩码
SIG_BLOCK:将第二个参数所描述的集合添加到当前进程阻塞的信号集中
SIG_UNBLOCK:将第二个参数所描述的集合从当前进程阻塞的信号集中删除
SIG_SETMASK:不管之前的阻塞信号,仅设置当前进程阻塞的集合为第二个参数描述的对象
如果set是空指针,则参数how的值没有意义,且不会更改线程的阻塞信号集,因此该调用可用于查询当前受阻塞的信号
需要注意的是,要阻塞SIGKILL或SIGSTOP信号是不可能的,这是由系统强制执行的,而不会导致错误,成功完成后,pthread_sigmask()返回0,否则,返回错误编号来之名错误,另外,如果由于某种原因pthread_sigmask()失败,线程的信号掩码将不会变化

线程属性控制

线程的属性主要围绕其所能申请资源,用户能够显示管理的线程属性主要是其栈空间信息
用户可以修改的线程的属性主要包括
detach state:设置创建一个线程后,该线程是处于分离状态还是可连接状态,即设置该线程是否可以被其他线程通过调用pthread_join而等待,默认值为PTHREAD_CREATE_JOINABLE
guardsize:创建的线程的守护区大小,默认值为PAGESIZE
schedparam:设置线程调度策略关联属性参数,例如基于优先级策略的优先级值
schedpolicy:设置创建的线程使用的特定调度策略,例如基于FIFO,时间片或者优先级
inheritsched:设置线程调度策略及关联属性是从创建线程中继承还是从属性对象中获得
stackaddr:指定创建的线程将要使用的堆栈,默认值为NULL
stacksize:创建线程的用户堆栈大小
contentionscope:线程争用范围
processor:将现场绑定到特定处理器
通过设置属性,可以指定一种不同于缺省行为的行为,使用pthread_creat()创建线程时,或者在运行过程中,都可以指定属性对象
属性对象是不透明的,而且不能通过赋值直接修改,系统提供了一组函数,用于初始化、配置和销毁线程属性

获取线程ID

线程最重要的属性为线程的ID值,此值不能修改,函数pthread_self()将返回当前线程的ID值,

pthread_t pthread_self()

在当前linux下,线程ID是某进程中是唯一的,如下所示,在不同的进程中创建的线程可能出现ID值相同的情况
而在内核中,每个线程都有自己的PID(但通过ps命令不能查看,也不会在/proc目录下生成对应PID编号的目录),用户可以通过sycall函数返回

初始化线程属性对象

在使用pthread_create()函数创建线程时,如果没有特殊要求,可以将第二个参数设置为NULL,从而使即将创建的线程获得的线程获得系统默认属性,库函数pthread_attr_init用来初始化线程属性对象

int pthread_attr_init(pthread_arrt_t *_attr)

此函数只有一个参数,即设置的新线程属性。
如果要销毁某个已经初始化的线程属性,可以调用,pthread_arrt_destory函数

int pthread_attr_destroy(pthread_attr_t *_attr);

初始化和配置属性后,属性便具有进程范围的作用域。使用属性时最好的方法即是在程序执行早期一次配置好所有必须的状态规范,然后根据需要引用相应的属性对象,使用属性对象具有以下两个主要优点

  • (1)使用属性对象可增加代码的可移植性
  • (2)应用程序中的状态规范已被简化

获取/设置线程detachstate属性

detachstate属性即创建一个线程后,设置该线程是处于分离状态还是可连接状态,处于分离状态将不能被其他线程通过thread_join等待。设置线程detachstate属性的函数声明如下

int pthread_att_setdetachstate(pthead_attr_t *_attr, int _detachstate);

pthread_attr_setdetachstate()用于设置已初始化属性对象attr中的detachstate属性。detachstate属性的新值将传递给detachstate参数中的此函数,其合法值为:
PTHREAD_CREATE_DETACHED:此选项使得使用attr创建的所有线程处于分离状态,线程终止时,系统将自动回收与带有此状态的的线程的相关的资源,这类线程不能被其他线程等待
PTHREAD_CREATE_JOINABLE:此选项使得attr创建的所有的线程处于可链接状态。线程终止时,不会回收与带有此状态的线程相关联的资源,如果要回收系统资源,则应用程序必须要在其他的线程调用pthread_detach()或pthread_join()函数
detachstate的默认值为PTHREAD_CREATE_JOINABLE
获取线程分离状态属性的函数声明如下:

int pthread_attr_getdetachstate(_const pthead_attr *_attr, int *_detachstate)

ptherad_attr_getdetachstate()可以从线程属性对象attr中检索detachstate属性值,并在detachstate参数中返回此值

获取/设置线程栈相关属性

获取/设置stack大小属性
pthrea_attr_setstacksize()用于设置已初始化属性对象attr中栈大小属性

int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t _stacksize)

此函数第一个参数为线程属性,第二个参数stacksize定义使用属性对象创建的线程的用户堆栈大小。stacksize属性的合法值包括
PTHREAD_STACK_MIN:此选项指定使用此属性对象创建的线程的用户栈大小将使用默认堆栈大小。此值为某个线程所需的最小堆栈大小,但对于所有线程来说,这个最小值可能无法接受
具体大小值:定义使用线程的用户堆栈大小的数值,必须大小或等于最小堆栈大小PTHREAD_STACK_MIN
函数pthread_attr_getstacksize()可以从线程属性对象attr中获取stacksize属性并在stacksize参数中返回此值

int pthread_attr_getstacksize(_const pthread_attr_t *_restrict _attr, size_t *_restrict _stacksize)

获取/设置stack地址属性

此属性选项指定创建的线程将要使用的栈基址。
pthread_attr_setstackaddr()用于设置已初始化属性对象attr中的栈基址属性

int pthread_attr_setstackaddr(pthread_attr_t *_attr, void *_stackaddr)

pthread_attr_getstackaddr()可以从线程属性对象attr中检索stackattr属性并在stackaddr参数中返回此值

int pthread_attr_getstackaddr(_const pthread_attr_t *_restrict _attr, void **_restrict _stackaddr)

获取/设置栈保护区属性

栈保护区属性允许应用程序指定使用此属性对象创建的线程的栈保护区大小,所指定守护区大小的单位为字节,大多数系统将守护区大小向上舍入为系统可配置变量PAGESIZE的倍数,如果指定了零值,则不会创建守护区。
pthread_attr_setguardsize()用于设置已初始化属性对象attr中的guardsize属性值。guardsize属性的新值将传递给guardsize参数中的此函数

int pthread_attr_setguardsize(pthread_attr_t *_attr, size_t _guardsize)

为应用程序设置栈保护区属性可以考虑一下yins溢出保护可能会导致系统资源浪费。如果应用程序创建大量线程,并且已知这些线程永远不会溢出其栈,则可以关闭溢出保护区,通过关闭溢出保护区,可以节约系统资源
线程在栈上分配大型数据结构时,可能需要较大的溢出保护区检测栈溢出
guardsize默认值为PAGESIZE字节
pthread_attr_getguardsize()可以从线程属性对象attr中读取guardsize属性值,并在guardsize参数中返回此值。如果守护区向上舍入为PAGESIZE的倍数,则此函数的调用必须将以前的pthread_attr_setguardsize()函数调用指定的守护区大小存储在guardsize参数中

int pthread_attr_getguardsize(_cosnt pthread_attr_t *_attr, size_t *_guardsize);

直接I/O:

#include <sys/types.h>
#include <unistd.h>
off_t lseek (int fd, off_t pos, int origin);

lseek()查找:对给定文件描述符设定指定值来在文件中查找
pos:为偏移量
origin:
        SEEK_CUR:当前文件位置
        SEEK_END:当前文件末尾
        SEEK_SET:当前文件起始
lseek()可以在文件末尾之后进行查找

read()的变体pread():比read()多添加了一个位置pos参数

#define _XOPEN_SOURCE 500
#include <unistd.h>
ssize_t pread (int fd, void *buf, size_t count, off_t pos);

write()的变体pwrite():同样比write()多添加了一个pos参数

#define _XOPEN_SOURCE 500
#include <unistd.h>
ssize_t pwrite (int fd, const void *buf, size_t count, off_t pos);

截短文件

#include <unistd.h>
#include <sys/types.h>
int ftruncate (int fd, off_t len);

#include <unistd.h>
#include <sys/types.h>
int truncate (const char *path, off_t len); 

ftruncate操作一个打开的并且可写的文件描述符
truncate操作一个path指定的一个可写文件
他们也可以将文件改变比原长度更长的文件,扩展出的直接将全部填充为零

I/O多路复用:

select():提供一种实现同步I/O多路复用的机制

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select (int n, fd_set *readfds, 
            fd_set *writefds, fd_set *exceptfds,struct timeval *timeout);
FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);               

nfds:是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!在Windows中这个参数的值无所谓,可以设置不正确。
readfds:(可选)指针,指向一组等待可读性检查的套接口。
writefds:(可选)指针,指向一组等待可写性检查的套接口。
exceptfds:(可选)指针,指向一组等待错误检查的套接口。
timeout:select()最多等待时间,对阻塞操作则为NULL。
timeout指向的timeval结构体的指针

#include <sys/time.h>
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};

FD_ZERO从指定集合中移除所有的文件描述符
FD_ZET向指定集合中添加一个文件描述符
FD_CLR从制定集合中移除一个文件描述符
FD_ISSET测试一个文件描述符在不在给定集合中
用select()可以实现可移植的sleep(),只要将三个集合至设为空,将超时值设置为非空来实现。
pselect():POSIX定义的自己的select()方法

#define _XOPEN_SOURCE 600
#include <sys/select.h>
int pselect (int n,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
const struct timespec *timeout,
const sigset_t *sigmask);
FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);

pselect()中timeout参数使用了timespec结构,而不是timeval结构。
增加了sigmask参数,以此来解决信号和等待文件描述符之间的竞争条件。
poll()系统调用是System V的IO多路复用解决方案。解决了一些select()的不足

#include <sys/poll.h>
int poll (struct pollfd *fds, unsigned int nfds, int timeout);

poll()使用一个简单的nfds个pollfd结构体构成的数组,fds指向该数组。结构体定义如下:

#include <sys/poll.h>
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};

ppoll()近似调用ppoll(),但是ppoll是Linux的专用调用

#define _GNU_SOURCE
#include <sys/poll.h>
int ppoll (struct pollfd *fds,
nfds_t nfds,
const struct timespec *timeout,
const sigset_t *sigmask);

虚拟文件系统:内核无需了解文件系统类型的情况下,使用文件系统函数和操作文件系统数据。程序员不许担心文件所在的文件系统或者介质。通用系统调用——read(),write()以及其他。

页缓存:一种在内存中保存最近在磁盘文件系统上访问过的数据方式。
页回写:将存有数据的“脏”缓冲区写到磁盘文件中,这就是所谓的回写。

缓冲输入输出

块大小:一般为512字节、1024字节、2048字节或者4096字节
标准I/O:
文件指针:FILE
打开文件:fopen()

#include <stdio.h>
FILE* fopen(const char * path, const char * mode);

通过文件描述符打开文件:fdopen()

#include <stdio.h>
FILE * fdopen (int fd, const char *mode);

关闭流:fclose()

#include <stdio.h>
int fclose (FILE *stream);

关闭所有的流:fcloseall()

#define _GNU_SOURCE
#include <stdio.h>
int fcloseall (void);

单字节读取:fgetc()

#include <stdio.h>
int fgetc (FILE *stream);

把字符回放入流中:ungetc()

#include <stdio.h>
int ungetc (int c, FILE *stream);

定位流:fseek()

#include <stdio.h>
int fseek (FILE *stream, long offset, int whence);

返回一个流的位置:ftell()

#include <stdio.h>
long ftell (FILE *stream);

刷新流:fflush(FILE *stream);

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值