st_mutex_lock协程锁介绍—StateThreads基础函数介绍
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
当使用多线程编程的时候,有时候为了保证 共享数据的一致性,会使用到线程锁 pthread_mutex_lock()
函数。StateThreads 也提供了一个类似的函数 st_mutex_lock()
协程锁。
提示:如果不熟悉多线程编程,以及线程同步的知识,请阅读《Unix环境高级编程》第11章节。
在进行多线程编程的时候,我们通常不知道 线程在什么时候被操作系统切走了,几乎在任何地方,操作系统都有可能进行线程切换。
在进行多协程编程的时候,我们通常是知道 在什么时候切走协程的,因为可以说协程的切换是主动切换的, st_read()
,st_writer()
,st_accept()
等函数都可能会产生协程切换。
虽然协程是主动切换的,但是他还是会切换,所以有些场景也需要用到 st_mutex_lock()
来保障数据的一致性。如下:
int a; //a 是全局变量
func test1(){
a = 100;
int b = st_read(); //从网络流读取 b
a += b
return a;
}
func test2(){
a = 50;
int b = st_read(); //从网络流读取 b
a += b
return a;
}
上面 test1()
跟 test2()
是两个协程,假设两个人拿到的 b 都是 10。设计者的目的是让 test1()
返回 110,test2()
返回 60。这样才是正确的结果。
但是实际上运行,可能真正的结果是 test1()
返回 110, test2()
返回 120。为什么呢?
因为中间被 st_read()
函数隔开了,所以代码真正的运行效果是这样的,两个协程启动之后,都阻塞在 st_read()
等待网络数据到来。假设 test1() 的数据先到,test1()
函数就会继续往下跑,然后把 a 变成 110。这时候 test2()
协程里的 a 也变成 110 了,因为 a 是全局变量。
那怎么解决这个问题呢?答:使用协程锁 st_mutex_lock
,伪代码如下:
int a; //a 是全局变量
func test1(){
st_mutex_lock();
a = 100;
int b = st_read(); //从网络流读取 b
a += b
st_mutex_unlock();
return a;
}
func test2(){
st_mutex_lock();
a = 50;
int b = st_read(); //从网络流读取 b
a += b
st_mutex_unlock();
return a;
}
协程锁与线程锁的用法是类似的。跟协程锁相关的还有一个 st_mutex_trylock() 函数,这函数如果获取不到锁会返回错误,不会一直阻塞。
关于 st_mutex_lock()
的内部实现分析,请阅读《st_mutex_lock协程锁源码分析》
参考资料