关于内核同步,顺序锁,读锁存在的意义

yangkunhenry 2019-05-18 12:10:09

u64 get_jiffies_64(void)
{
unsigned long seq;
u64 ret;

do {
seq = read_seqbegin(&xtime_lock);
ret = jiffies_64;
}while(read_seqretry(&xtime_lock),seq));

return ret;
}


上面get_jiffies_64的方法,使用read_seqbegin的意义是什么?

我感觉不用也可以

对应的定时器中断更新jiffies的值用了顺序写锁


write_seqlock(&xtime_lock);
jiffies_64 += 1;
write_sequnlock(&xtime_lock);
...全文
209 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
tq1086 2019-05-31
  • 打赏
  • 举报
回复
5楼说得很好,我补充一点。这就是数据库里读脏数据的情况。如果没有锁进行保护,可能会出现下面的执行序列: 线程1:写jiffies高32字节。 线程2:读jiffies。 线程1:写jiffies低32字节。 这时线程2读到的值是脏数据,是错误的、不可靠的数据。
yangkunhenry 2019-05-26
  • 打赏
  • 举报
回复
引用 6 楼 林多 的回复:
[quote=引用 5 楼 林多 的回复:] [quote=引用 4 楼 yangkunhenry 的回复:] [quote=引用 3 楼 林多 的回复:] 首先,基本概念。 顺序锁中,写锁优先级,高于读锁。。。假设正在读,也允许写(如果没有其他写操作)。。 这样的话,写操作就不需要的等待了。。但是,读操作,就必须要判断当前读的内容,是不是有效的。(假设读时,正好进行写)。 为了避免这个问题,使用到了顺序计数器。。。其实就是 seqlock_t中的sequence字段。。。 读操作时,读前获取一次sequence,读后获取一次sequence。如果两次相同,说明读取有效。如果不相同,需要再次读取。 写操作时,write_seqlock,将sequence加1(奇数),write_sequnlock将sequence加1(偶数)。。写操作中,为奇数。写完,就变成偶数了。 read_seqbegin,用来获取当前的sequence。 read_seqretry,用来判断传入的sequence,与目前状态下的计数器是不是相等,不相等返回1。。。 到这里这段代码的使用read_seqbegin的意图,就很明显了。保证读的是有效值。

{
    unsigned long seq;
    u64 ret;
     
    do {
       // 获取 顺序数
        seq = read_seqbegin(&xtime_lock);
        ret = jiffies_64;
     // 如果之前获取的顺序数,与当前顺序数不一样(有写操作正在进行)。重新读取。
    }while(read_seqretry(&xtime_lock),seq));
     
    return ret;
}
谢谢大神回复。 在这里的例子中,写锁其实是一个很简单的 加一 的操作,在我看来,在读取的时候要么读到之前的值,要么读到加一之后的值,而且读到这两种值都是正确的。当然如果“写”的行为是一个比较复杂的操作的话确实是需要采用代码中所写的方式。 只是觉得当前这种情况不用也可以。 [/quote] 这种情况的下,仍然需要加锁的。 在32位架构下,对64位的读取,不是原子的。也就是说,读取高、低32位,这段间隔时。如果,节拍发生了更新,就会读到一个异常的值。 因此,不能直接读取64位的节拍。。。但是如果,非要读取64位的节拍,就需要使用get_jiffies_64,这种添加了同步机制的函数。 ----英文解释 You might wonder why jiffies has not been directly declared as a 64-bit unsigned long long integer on th 80x86 architecture. The answer is that access to 64-bit variables in 32-bit architectures cannot be done atomically. Therefor , every read operation on the whole 64 bit requires some synchronization technique to ensure that the counter is not updated while two 32-bit half-counters are read; as s consequence, every 64-bit read operation is significantly slower than a 32-bit read operation.[/quote] 下面源码可以看出来,在64位上,就是直接返回。。而在32位上,u64 get_jiffies_64(void); 这个函数。
/* some arch's have a small-data section that can be accessed register-relative
 * but that can only take up to, say, 4-byte variables. jiffies being part of
 * an 8-byte variable may not be correctly accessed unless we force the issue
 */
#define __jiffy_data  __attribute__((section(".data")))
 
 
/*
 * The 64-bit value is not atomic - you MUST NOT read it
 * without sampling the sequence number in xtime_lock.
 * get_jiffies_64() will do this for you as appropriate.
 */
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;
 
 
#if (BITS_PER_LONG < 64)
u64 get_jiffies_64(void);
#else
static inline u64 get_jiffies_64(void)
{
    return (u64)jiffies;
}
[/quote]真赞啊!!!谢谢!
林多 2019-05-23
  • 打赏
  • 举报
回复
引用 5 楼 林多 的回复:
[quote=引用 4 楼 yangkunhenry 的回复:] [quote=引用 3 楼 林多 的回复:] 首先,基本概念。 顺序锁中,写锁优先级,高于读锁。。。假设正在读,也允许写(如果没有其他写操作)。。 这样的话,写操作就不需要的等待了。。但是,读操作,就必须要判断当前读的内容,是不是有效的。(假设读时,正好进行写)。 为了避免这个问题,使用到了顺序计数器。。。其实就是 seqlock_t中的sequence字段。。。 读操作时,读前获取一次sequence,读后获取一次sequence。如果两次相同,说明读取有效。如果不相同,需要再次读取。 写操作时,write_seqlock,将sequence加1(奇数),write_sequnlock将sequence加1(偶数)。。写操作中,为奇数。写完,就变成偶数了。 read_seqbegin,用来获取当前的sequence。 read_seqretry,用来判断传入的sequence,与目前状态下的计数器是不是相等,不相等返回1。。。 到这里这段代码的使用read_seqbegin的意图,就很明显了。保证读的是有效值。

{
    unsigned long seq;
    u64 ret;
     
    do {
       // 获取 顺序数
        seq = read_seqbegin(&xtime_lock);
        ret = jiffies_64;
     // 如果之前获取的顺序数,与当前顺序数不一样(有写操作正在进行)。重新读取。
    }while(read_seqretry(&xtime_lock),seq));
     
    return ret;
}
谢谢大神回复。 在这里的例子中,写锁其实是一个很简单的 加一 的操作,在我看来,在读取的时候要么读到之前的值,要么读到加一之后的值,而且读到这两种值都是正确的。当然如果“写”的行为是一个比较复杂的操作的话确实是需要采用代码中所写的方式。 只是觉得当前这种情况不用也可以。 [/quote] 这种情况的下,仍然需要加锁的。 在32位架构下,对64位的读取,不是原子的。也就是说,读取高、低32位,这段间隔时。如果,节拍发生了更新,就会读到一个异常的值。 因此,不能直接读取64位的节拍。。。但是如果,非要读取64位的节拍,就需要使用get_jiffies_64,这种添加了同步机制的函数。 ----英文解释 You might wonder why jiffies has not been directly declared as a 64-bit unsigned long long integer on th 80x86 architecture. The answer is that access to 64-bit variables in 32-bit architectures cannot be done atomically. Therefor , every read operation on the whole 64 bit requires some synchronization technique to ensure that the counter is not updated while two 32-bit half-counters are read; as s consequence, every 64-bit read operation is significantly slower than a 32-bit read operation.[/quote] 下面源码可以看出来,在64位上,就是直接返回。。而在32位上,u64 get_jiffies_64(void); 这个函数。
/* some arch's have a small-data section that can be accessed register-relative
 * but that can only take up to, say, 4-byte variables. jiffies being part of
 * an 8-byte variable may not be correctly accessed unless we force the issue
 */
#define __jiffy_data  __attribute__((section(".data")))
 
 
/*
 * The 64-bit value is not atomic - you MUST NOT read it
 * without sampling the sequence number in xtime_lock.
 * get_jiffies_64() will do this for you as appropriate.
 */
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;
 
 
#if (BITS_PER_LONG < 64)
u64 get_jiffies_64(void);
#else
static inline u64 get_jiffies_64(void)
{
    return (u64)jiffies;
}
林多 2019-05-23
  • 打赏
  • 举报
回复
引用 4 楼 yangkunhenry 的回复:
[quote=引用 3 楼 林多 的回复:] 首先,基本概念。 顺序锁中,写锁优先级,高于读锁。。。假设正在读,也允许写(如果没有其他写操作)。。 这样的话,写操作就不需要的等待了。。但是,读操作,就必须要判断当前读的内容,是不是有效的。(假设读时,正好进行写)。 为了避免这个问题,使用到了顺序计数器。。。其实就是 seqlock_t中的sequence字段。。。 读操作时,读前获取一次sequence,读后获取一次sequence。如果两次相同,说明读取有效。如果不相同,需要再次读取。 写操作时,write_seqlock,将sequence加1(奇数),write_sequnlock将sequence加1(偶数)。。写操作中,为奇数。写完,就变成偶数了。 read_seqbegin,用来获取当前的sequence。 read_seqretry,用来判断传入的sequence,与目前状态下的计数器是不是相等,不相等返回1。。。 到这里这段代码的使用read_seqbegin的意图,就很明显了。保证读的是有效值。

{
    unsigned long seq;
    u64 ret;
     
    do {
       // 获取 顺序数
        seq = read_seqbegin(&xtime_lock);
        ret = jiffies_64;
     // 如果之前获取的顺序数,与当前顺序数不一样(有写操作正在进行)。重新读取。
    }while(read_seqretry(&xtime_lock),seq));
     
    return ret;
}
谢谢大神回复。 在这里的例子中,写锁其实是一个很简单的 加一 的操作,在我看来,在读取的时候要么读到之前的值,要么读到加一之后的值,而且读到这两种值都是正确的。当然如果“写”的行为是一个比较复杂的操作的话确实是需要采用代码中所写的方式。 只是觉得当前这种情况不用也可以。 [/quote] 这种情况的下,仍然需要加锁的。 在32位架构下,对64位的读取,不是原子的。也就是说,读取高、低32位,这段间隔时。如果,节拍发生了更新,就会读到一个异常的值。 因此,不能直接读取64位的节拍。。。但是如果,非要读取64位的节拍,就需要使用get_jiffies_64,这种添加了同步机制的函数。 ----英文解释 You might wonder why jiffies has not been directly declared as a 64-bit unsigned long long integer on th 80x86 architecture. The answer is that access to 64-bit variables in 32-bit architectures cannot be done atomically. Therefor , every read operation on the whole 64 bit requires some synchronization technique to ensure that the counter is not updated while two 32-bit half-counters are read; as s consequence, every 64-bit read operation is significantly slower than a 32-bit read operation.
yangkunhenry 2019-05-22
  • 打赏
  • 举报
回复
引用 3 楼 林多 的回复:
首先,基本概念。 顺序锁中,写锁优先级,高于读锁。。。假设正在读,也允许写(如果没有其他写操作)。。 这样的话,写操作就不需要的等待了。。但是,读操作,就必须要判断当前读的内容,是不是有效的。(假设读时,正好进行写)。 为了避免这个问题,使用到了顺序计数器。。。其实就是 seqlock_t中的sequence字段。。。 读操作时,读前获取一次sequence,读后获取一次sequence。如果两次相同,说明读取有效。如果不相同,需要再次读取。 写操作时,write_seqlock,将sequence加1(奇数),write_sequnlock将sequence加1(偶数)。。写操作中,为奇数。写完,就变成偶数了。 read_seqbegin,用来获取当前的sequence。 read_seqretry,用来判断传入的sequence,与目前状态下的计数器是不是相等,不相等返回1。。。 到这里这段代码的使用read_seqbegin的意图,就很明显了。保证读的是有效值。

{
    unsigned long seq;
    u64 ret;
     
    do {
       // 获取 顺序数
        seq = read_seqbegin(&xtime_lock);
        ret = jiffies_64;
     // 如果之前获取的顺序数,与当前顺序数不一样(有写操作正在进行)。重新读取。
    }while(read_seqretry(&xtime_lock),seq));
     
    return ret;
}
谢谢大神回复。 在这里的例子中,写锁其实是一个很简单的 加一 的操作,在我看来,在读取的时候要么读到之前的值,要么读到加一之后的值,而且读到这两种值都是正确的。当然如果“写”的行为是一个比较复杂的操作的话确实是需要采用代码中所写的方式。 只是觉得当前这种情况不用也可以。
林多 2019-05-21
  • 打赏
  • 举报
回复
首先,基本概念。 顺序锁中,写锁优先级,高于读锁。。。假设正在读,也允许写(如果没有其他写操作)。。 这样的话,写操作就不需要的等待了。。但是,读操作,就必须要判断当前读的内容,是不是有效的。(假设读时,正好进行写)。 为了避免这个问题,使用到了顺序计数器。。。其实就是 seqlock_t中的sequence字段。。。 读操作时,读前获取一次sequence,读后获取一次sequence。如果两次相同,说明读取有效。如果不相同,需要再次读取。 写操作时,write_seqlock,将sequence加1(奇数),write_sequnlock将sequence加1(偶数)。。写操作中,为奇数。写完,就变成偶数了。 read_seqbegin,用来获取当前的sequence。 read_seqretry,用来判断传入的sequence,与目前状态下的计数器是不是相等,不相等返回1。。。 到这里这段代码的使用read_seqbegin的意图,就很明显了。保证读的是有效值。

{
    unsigned long seq;
    u64 ret;
     
    do {
       // 获取 顺序数
        seq = read_seqbegin(&xtime_lock);
        ret = jiffies_64;
     // 如果之前获取的顺序数,与当前顺序数不一样(有写操作正在进行)。重新读取。
    }while(read_seqretry(&xtime_lock),seq));
     
    return ret;
}
yangkunhenry 2019-05-19
  • 打赏
  • 举报
回复
哪位大神给点提点?实在不太明白这里这么做的原因

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧