linux并发concurrency控制

本文介绍了Linux中解决竞态条件的几种常见方法,包括中断屏蔽、原子操作、自旋锁、信号量及互斥体,并详细阐述了每种机制的特点与应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解决竞态(race conditions)最根本的途径是对共享资源的互斥访问,访问共享资源的代码区被称为临界区(critical sections),对临界区的代码需要以某种互斥机制加以保护。
常见的互斥机制有:中断屏蔽、原子操作、自旋锁、信号量、互斥体。

1. 中断屏蔽
由于linux内核的进程调度和异步IO等操作都是依赖中断来实现的,所以中断屏蔽也可以避免内核强占进程之间的竞态发生。
定义在linux/irqflags.h,实现在asm/irqflags.h中。
local_irq_disable();
local_irq_enable();

local_irq_save(flags);
local_irq_restore(flags);

local_bh_disable();
local_bh_enable();

2. 原子操作
原子操作分类:整型原子操作和位原子操作
整型原子操作
asm/atomic.h
void atomic_set(atomic_t *v, int i);
atomic_t v = ATOMIC_INIT(0);
atomic_read(atomic_t *v);
void atomic_add(int i, atomic_t *v);
void atomic_sub(int i, atomic_t *v);
void atomic_inc(atomic_t *v);
void atomic_dec(atomic_t *v);
int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(atomic_t *v);
操作后测试是否为0,为0返回true,否则返回false。
int atomic_add_return(int i, atomic_t *v);
操作后返回新值。

位原子操作
asm/bitops.h
void set_bit(nr, void *addr);
void clear_bit(nr, void *addr);
void change_bie(nr, void *addr);
test_bit(nr, void *addr);
int test_and_set_bit(nr, void *addr);
int test_and_clear_bit(nr, void *addr);
int test_and_change_bit(nr, void *addr);

3. 自旋锁
1)自旋锁主要针对SMP或单CPU且内核可强占的情况,对于单CPU且内核不可强占的系统自旋锁退化为空操作。
2)在单CPU且内核可强占的系统中,自旋锁持有期间内核的强占被禁止。

使用注意:
1)不能递归持有自旋锁。
2)持有自旋锁后不能阻塞。

linux/spinlock_types.h
spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);
spin_trylock(&lock);
spin_unlock(&lock);

spin_lock_irq();
spin_unlock_irq();
spin_lock_irqsave();
spin_unlock_irqrestore();
spin_lock_bh();
spin_unlock_bh();

读写自旋锁
写操作时最多只能有一个写进程。
顺序锁

4. 信号量
linux/semaphore.h,实现在ipc/sem.c和kernel/semaphore.c中。
struct semaphore sem;
void sema_init(struct semaphore *sem, int val);
void down(struct semaphore *sem);
int down_interruptible(struct semaphore *sem);
int down_trylock(struct semaphore *sem);
void up(struct semaphore *sem);

5. 互斥体
linux/mutex.h       kernel/mutex.c
struct mutex mymutex;
mutex_init(&mymutex);
void fastcall mutex_lock(struct mutex *lock);
int fastcall mutex_lock_interruptible(struct mutex *lock);
int fastcall mutex_trylock(struct mutex *lock);
void fastcall mutex_unlock(struct mutex *lock);

总结
1、信号量是进程级的,用于多个进程之间对资源的互斥。如果竞争失败,会发生进程上下文切换,当前进程进入休眠状态。
2、自旋锁得不到锁时会在原地自旋一直到获取锁,它节省了上下文的切换时间,所以一般用于要保护的临界区访问时间比较短的时候,否则会降低系统效率。

自旋锁和信号量选用原则
1、临界区执行时间比较小时,采用自旋锁,否则使用信号量。
2、信号量所包含的临界区包含可能引起阻塞的代码,而自旋锁要绝对避免在临界区使用阻塞代码。
3、信号量运用进程上下文,若要运于中断中,应用down_trylock()方式进行,不能获取就立即返回,避免阻塞。

 

参考:

1. linux设备驱动开发详解 宋宝华

2. linux并发控制

### 配置Linux系统上的Ollama以支持并发操作 为了使Ollama能够在Linux环境中支持并发操作,需对默认的服务设置进行修改。这涉及到编辑`systemd`服务文件来调整启动参数。 #### 修改Systemd服务配置 通过编辑`systemd`服务文件可实现此目的: ```bash sudo systemctl edit ollama.service ``` 上述命令会打开一个临时文件用于追加自定义配置[^3]。如果希望直接编辑完整的服务文件,则应使用以下方法: ```bash sudo vim /etc/systemd/system/ollama.service ``` 在该文件中找到`[Service]`部分下的`ExecStart`指令,并在其基础上添加必要的参数以启用并发功能。通常情况下,可能需要增加内存分配或线程数等选项,具体取决于应用程序的需求和服务器硬件条件。 对于某些应用而言,在同一行内加入类似`--concurrency=NUM`这样的标志可能是有效的做法之一,其中`NUM`代表期望的最大并发数量。然而确切的语法应当参照官方文档获取最准确的信息。 完成更改之后保存并关闭文本编辑器。为了让新的设定生效,记得重启对应的`systemd`单元: ```bash sudo systemctl daemon-reload sudo systemctl restart ollama.service ``` 以上步骤能够帮助实现在Linux平台上配置Ollama以更好地利用系统资源执行并发任务的目的。 ```python # 示例Python脚本验证服务状态 (仅作示意用途) import subprocess def check_service_status(service_name): try: output = subprocess.check_output(['systemctl', 'status', service_name]) print(f"{service_name} status:\n{output.decode()}") except Exception as e: print(e) check_service_status('ollama') ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值