linux 系统编程-学习笔记9--线程的同步互斥锁、读写锁/select/poll

线程的同步:
解决方式:1.互斥锁 2.读写锁

进程的同步:记录锁
多个进程对同一个文件操作

int fcntl(int fd, int cmd, ... /* arg */ );
通过文件描述符根据cmd选项对文件进行操作

cmd:
F_DUPFD : 复制一个现有的文件描述符
F_SETLKW : 设置记录锁

struct flock {
...
short l_type;    /* Type of lock: 
   F_RDLCK, 读锁
   F_WRLCK, 写锁
   F_UNLCK 解锁
 */
short l_whence;  /* How to interpret l_start:
   SEEK_SET,
   SEEK_CUR,
   SEEK_END */
off_t l_start;   /* Starting offset for lock :一般给0,由系统自动判断*/
off_t l_len;     /* Number of bytes to :一般给0,由系统自动判断*/
...
};






====================================================================================
阻塞: 一旦数据1没有到达,被阻塞了,即使数据2和数据3到达也不会被处理


if(数据1到达) ===>一直阻塞在这里
{
处理数据1;
}
else if(数据2到达)
{
处理数据2;
}
else if(数据3到达)
{
处理数据3;
}

非阻塞:数据1没有到达,被阻塞了,在规定的时间内轮询,如若超过规定的时间,则退出,让
其他数据执行,所以数据2和数据3到达会被处理,不会阻塞[时间片]

if(数据1到达) ===>一直阻塞在这里
{
处理数据1;
}
else if(数据2到达)
{
处理数据2;
}
else if(数据3到达)
{
处理数据3;


}
注意:
1.一般涉及到终端或者网络需要解决阻塞问题
2.普通文件不需要解决阻塞问题【系统已经处理了】


_________________________________________________________________________________________
1.在同一个进程中操作一个描述符,不涉及阻塞问题


2.在同一个进程中操作两个或者以上的文件描述符,需要解决阻塞问题
怎么解决?
1).在同一个进程中,都以非阻塞的方式打开
在规定的时间内不停的轮询==》浪费cpu资源

-----------------------------------------------------------------------------------------------
F_GETFL (void)
Read the file status flags; arg is ignored.

F_SETFL (long)
Set  the  file  status  flags  to the value specified by arg.  File access mode (O_RDONLY,
O_WRONLY, O_RDWR) and file creation flags
(i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored.  On Linux  this
command  can  only  change  the  O_APPEND,  O_ASYNC,
O_DIRECT, O_NOATIME, and O_NONBLOCK flags.
-----------------------------------------------------------------------------------------------


2).在一个进程中,开辟多个线程【一读终端,一个读鼠标】
:需要解决线程间的同步问题--》使得程序变得复杂

3).fork一个新的进程,一个进程处理一个文件描述符
:使得程序更加复杂


4.一种比较好的方式,设置异步方式
:不是所有的系统都支持异步.......


______________________________________________________
5.比较好的,常用的方式:I/O多路复用
a.select机制【轮询】
:把所有关心的文件描述符都加入到一个集合中,让内核为我们判断,当描述符准备好了[不阻塞]
返回准备好的文件描述符给我们[程序员],之后我们操作的文件描述符就不会发送阻塞

int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
nfds : 最大的文件描述符+1
fd_set: 类型
typedef struct {
unsigned long fds_bits [__FDSET_LONGS];
} __kernel_fd_set;


readfds : 所关心的读的集合
writefds: 所关心的写的集合 [一般不关心]
execptfds:所关心的异常的集合 [一般不关心]


timeout : 你愿意等待多少时间
struct timeval {
long    tv_sec;         /* seconds */
long    tv_usec;        /* microseconds */
};
NULL : 永远等待
0    : 不等待
!= 0 : 等待指定的时间

返回值:
成功: > 0  返回准好的个数
超时: = 0  
失败: -1

______________________________________________________
void FD_CLR(int fd, fd_set *set);
把文件描述符fd从集合set中删除
____________________________________________________
int  FD_ISSET(int fd, fd_set *set);
判断文件描述符fd是否在集合set中

void FD_SET(int fd, fd_set *set);
把文件描述符fd加入到集合set中

void FD_ZERO(fd_set *set);
清空集合set


select缺点:
1.每次都需要把描述符重新加入到集合中
2.每次都要重新设置等待时间
[==========================================================================]

b.poll机制
内部实现和select机制一样,但是比select更为高效,poll机制没有采用低效的三位[读集合,写集合,异常集合]
而是把所有关心的描述符都加入到一个结构体数组struct pollfd中,由内核判断,返回准备就绪的描述符


____________________________________________________________
select缺点:
1.每次都需要把描述符重新加入到集合中
2.每次都要重新设置等待时间


poll  : 文件描述符只需要加入一次
_____________________________________________________________


int poll(struct pollfd *fds, nfds_t nfds, int timeout);

struct pollfd {
int fd;//文件描述符
short events;//告诉内核我[程序员]要做什么事情
short revents;//内核返回给我,它到底做了什么事情
};

nfds   : 加入到数组中的 文件描述符的个数
timeout: 表示愿意等待多少时间
-1   :  永远等待
0    : 不等待
>0   :  等待给定的时间


返回值:
 > 0   : 表示至少有一个文件描述符准备就绪
 = 0   : 超时
 < 0   : 异常返回


#define POLLIN          0x001           /* There is data to read.  */

[==========================================================================]

b.poll机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值