RTE Read-Write Locks 读写锁函数

读写锁特性:
一次只有一个线程可以占有写模式的读写锁, 但是可以有多个线程同时占有读模式的读写锁. 正是因为这个特性,
当读写锁是写加锁状态时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞.
当读写锁在读加锁状态时, 所有试图以读模式对它进行加锁的线程都可以得到访问权, 但是如果线程希望以写模式对此锁进行加锁, 它必须直到所有的线程释放锁.
通常, 当读写锁处于读模式锁住状态时, 如果有另外线程试图以写模式加锁, 读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁长期占用, 而等待的写模式锁请求长期阻塞.
读写锁适合于对数据结构的读次数比写次数多得多的情况. 因为, 读模式锁定时可以共享, 以写模式锁住时意味着独占, 所以读写锁又叫共享-独占锁.

接下来我们看下DPDK 源码
结构定义:
typedef struct {
volatile int32_t cnt; /**< -1 when W lock held, > 0 when R locks held. */
} rte_rwlock_t;
注:volatile 所修饰的变量随时都可能发生变化,每次使用该值必须从内存地址中读取,而不是直接从寄存器中拷贝内容。

// 写锁,会一直循环,除非原子已经控制住

static inline void
rte_rwlock_write_lock(rte_rwlock_t rwl)
{
int32_t x;
int success = 0;
while (success == 0) {
x = rwl->cnt;
/
a lock is held */
if (x != 0) {
rte_pause();
continue;
}
success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
0, -1);
}
}

写锁会一直循环来获取变量状态,判断有读,有写,自己就循环,否则,把原子设置为-1,
static inline void
rte_rwlock_write_unlock(rte_rwlock_t *rwl)
{
rte_atomic32_inc((rte_atomic32_t *)(intptr_t)&rwl->cnt);
}
解锁是原子操作+1

注:ret_pause() PAUSE指令给处理器提了个醒:这段代码序列是个循环等待。处理器利用这个提示可以避免在大多数情况下的内存顺序违规,这将大幅提升性能。因为这个原因,所以推荐在循环等待中使用PAUSE指令。

原子操作函数
rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
{
unsigned int ret = 0;

asm volatile(
		"\tlwsync\n"
		"1:\tlwarx %[ret], 0, %[dst]\n"
		"cmplw %[exp], %[ret]\n"
		"bne 2f\n"
		"stwcx. %[src], 0, %[dst]\n"
		"bne- 1b\n"
		"li %[ret], 1\n"
		"b 3f\n"
		"2:\n"
		"stwcx. %[ret], 0, %[dst]\n"
		"li %[ret], 0\n"
		"3:\n"
		"isync\n"
		: [ret] "=&r" (ret), "=m" (*dst)
		: [dst] "r" (dst),
		  [exp] "r" (exp),
		  [src] "r" (src),
		  "m" (*dst)
		: "cc", "memory");

return ret;

}

static inline void
rte_rwlock_read_lock(rte_rwlock_t *rwl)
{
int32_t x;
int success = 0;

while (success == 0) {
	x = rwl->cnt;
	/* write lock is held */
	if (x < 0) {
		rte_pause();
		continue;
	}
	success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
				      x, x + 1);
}

}

#读锁,判断是否有在写的操作,如果有的话循环,如果没有的话+1 操作
static inline void
rte_rwlock_read_lock(rte_rwlock_t *rwl)
{
int32_t x;
int success = 0;

while (success == 0) {
	x = rwl->cnt;
	/* write lock is held */
	if (x < 0) {
		rte_pause();
		continue;
	}
	success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
				      x, x + 1);
}

}

static inline void
rte_rwlock_read_unlock(rte_rwlock_t *rwl)
{
rte_atomic32_dec((rte_atomic32_t *)(intptr_t)&rwl->cnt);
}

解读锁只需要减一即可

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
rte(runtime environment)是高性能计算集群中常用的软件库,包含各种实用函数和工具,其中包括rte_write函数rte_write函数主要用于将数据写入文件或输出到终端。该函数支持类似于printf的格式化输出,用户可以指定输出的格式,如整数、浮点数、字符串等等。下面详细介绍rte_write函数的使用方法和注意事项。 rte_write函数的语法格式如下: int rte_write(int fd, const void *data, size_t len); 其中,fd指定打开的文件描述符,data是指向要写入的数据的指针,len是写入数据的长度。函数返回写入的字节数,如果写入失败则返回负数。 在使用rte_write函数前,需要确保文件已经打开或输出流已经建立。可以使用open函数打开要写入的文件,获得文件描述符,然后将文件描述符传递给rte_write函数。如果要将输出流重定向到标准输出,则可以使用freopen函数。此外,在使用rte_write函数时还需要注意以下几点: 1.写入数据的长度len必须小于等于实际数据的长度,否则可能会写入超出范围的数据。 2.在写入数据时尽量避免使用循环,多次调用rte_write,应该尽量将数据存储在一个buffer中,然后一次性调用rte_write函数写入。 3.在使用rte_write函数后,需要用close函数关闭文件描述符或者fflush函数刷新输出缓冲区,确保数据写入文件或者输出流。 总之,rte_write函数是高性能计算集群中常用的输出函数,可以方便快捷地将数据输出到文件或者控制台。在使用该函数时需要注意数据长度和文件描述符的正确性,以及适时刷新输出缓冲区,确保程序正常运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值