《原子嵌入式Linux驱动开发详解与实战》第9章并发与竞争学习
[复制链接]
本帖最后由 常见泽1 于 2024-4-13 14:58 编辑
第八章第九章 LINUX并发与竞争学习心得
一原子操作
原子(atomic)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意为“不可被中断的一个或一系列操作”,可以保证指令以原子的方式运行,即执行过程不被打断,如果被中断则可能会引起执行结果和预期不符。
atomic_read(atomic_t * v);
该函数对原子类型的变量进行原子读操作,它返回原子类型的变量v的值。
atomic_set(atomic_t * v, int i);
该函数设置原子类型的变量v的值为i。
void atomic_add(int i, atomic_t *v);
该函数给原子类型的变量v增加值i。
atomic_sub(int i, atomic_t *v);
该函数从原子类型的变量v中减去i。
int atomic_sub_and_test(int i, atomic_t *v);
该函数从原子类型的变量v中减去i,并判断结果是否为0,如果为0,返回真,否则返回假。
void atomic_inc(atomic_t *v);
该函数对原子类型变量v原子地增加1。
void atomic_dec(atomic_t *v);
该函数对原子类型的变量v原子地减1。
int atomic_dec_and_test(atomic_t *v);
该函数对原子类型的变量v原子地减1,并判断结果是否为0,如果为0,返回真,否则返回假。
int atomic_inc_and_test(atomic_t *v);
该函数对原子类型的变量v原子地增加1,并判断结果是否为0,如果为0,返回真,否则返回假。
int atomic_add_negative(int i, atomic_t *v);
该函数对原子类型的变量v原子地增加I,并判断结果是否为负数,如果是,返回真,否则返回假。
int atomic_add_return(int i, atomic_t *v);
该函数对原子类型的变量v原子地增加i,并且返回指向v的指针。
int atomic_sub_return(int i, atomic_t *v);
该函数从原子类型的变量v中减去i,并且返回指向v的指针。
int atomic_inc_return(atomic_t * v);
该函数对原子类型的变量v原子地增加1并且返回指向v的指针。
int atomic_dec_return(atomic_t * v);
该函数对原子类型的变量v原子地减1并且返回指向v的指针。
二自旋锁
原子操作只能对整型变量或者位进行保护,但是在实际的使用环境中不可能只有整形变量或位知名简单的临界区。
自旋锁的自旋就是原地打转的意思,原地打转的目的是等待自旋锁可以用,可以访问共享资源。
缺点:
等待自旋锁的线程会一直处于自旋状态,这样会浪费处理器时间,降低系统性能,所以自旋锁的持有时间不能太长。因此自旋锁适用于短时间的轻量级加锁。
自旋锁为互斥设备,只有上锁与解锁两种状态
自旋锁示例:
测试例程:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
//#include<vector>
pthread_spinlock_t spin_lock;
char num = 0;
void xprintf(char *str)
{
int i = 0;
while(str[i] != '\0')
{
printf("%c", str[i++]);
fflush(stdout);
sleep(1);
}
return NULL;
}
void *producer(void *arg)
{
int times = 1000000;
while(times--)
{
pthread_spin_lock(&spin_lock);
num+=1;
printf("%d",num);
pthread_spin_unlock(&spin_lock);
}
}
void *comsumer(void *arg)
{
int times = 1000000;
while(times--)
{
pthread_spin_lock(&spin_lock);
num-=1;
printf("%d",num);
pthread_spin_unlock(&spin_lock);
}
}
int main()
{
pthread_spin_init(&spin_lock,0);
pthread_t thread1,thread2;
pthread_create(&thread1,NULL,producer,NULL);
pthread_create(&thread2,NULL,comsumer,NULL);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
printf("%d",num);
return 0;
}
三信号量
信号量这个概念在ucos等单片机的微型操作系统里其实就已经有学过,算是有些相似吧,但是还是有区别的
信号量的特点:
1信号量可以使等待资源现成进入休眠状态,因此适用于那些占用资源比较久的场合
2信号量不能用于终端中,因为信号量会引起休眠, 中断不能休眠
3如果共享资源的持有时间比较短,那就不适合使用信号量了,因为频繁的休眠、切换现成引起的开销要远大于信号量带来的那点优势
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t sem;
void xprintf(char *str)
{
int i = 0;
while(str[i] != '\0')
{
printf("%c", str[i++]);
fflush(stdout);
sleep(1);
}
return NULL;
}
void *task_fun1(void *arg)
{
sem_wait(&sem);
xprintf((char *)arg);
sem_post(&sem);
return NULL;
}
void *task_fun2(void *arg)
{
sem_wait(&sem);
xprintf((char *)arg);
sem_post(&sem);
return NULL;
}
int main(int argc, char const *argv[])
{
sem_init(&sem, 0, 1);
pthread_t pthid1, pthid2;
pthread_create(&pthid1, NULL, task_fun1, "TASK1");
pthread_create(&pthid2, NULL, task_fun2, "TASK2");
pthread_join(pthid1, NULL);
pthread_join(pthid2, NULL);
sem_destroy(&sem);
return 0;
}
这里用到了多线程,所以要加 -pthread
gcc sem_thread.c -lpthread
实操进行测试
|