3. Qt深入 线程安全函数与可重入函数
PS:额外知识点,共享数据的互斥锁要注意颗粒度,颗粒度越大,效率越低
0. 参考:https://blog.csdn.net/gaoyuelon/article/details/126672977

1. 先来看一个不可重入的函数版本:
// 不可重入版本
void caculate(int a, int b,int* sum)
{static int c; // 使用了静态变量或全局变量,c = a + b; //当线程1执行完这一步,得到c=3, 此时线程2开始执行得到c=3+4=7,由于c是全局变量,所以线程1的c也是7*sum = c; //线程1和线程2得到的sum=7, 线程1计算错误
}
// 假设线程1调用
int sum1;
caculate(1, 2, &sum1);
// 线程2调用
int sum2;
caculate(3, 4, &sum2);
2. 可重入但非线程安全的版本:可重入函数可以被多线程调用,但前提是每个线程调用都是用自己的数据。
注意:线程1在自己的线程中创建了x1,x2,sum1变量传入caculate,线程2在自己线程创建了x3,x4,sum2变量传入caculate,也就是这两个线程分别使用了自己的数据作为caculate参数,这样调用是没有问题的。
// 可重入版本,由于函数内都是临时变量,各个线程没有共享同一个变量,所以这个函数是可重入的
void caculate(int a, int b, int* sum)
{*sum = a + b;int d = sum + 1;...
}// 假设线程1调用
int sum1;
int x1 = 1, x2 = 2;
caculate(x1, x2, &sum1);
// 线程2调用
int sum2;
int x3 = 3, x4 = 4;
caculate(x3, x4, &sum2);
3. 那么上面这个版本为什么是非线程安全呢?
注意,上面两个线程各自创建了sum1,sum2变量作为caculate参数,这样一来两个线程调用caculate时完全没有共用的变量,所以这两个线程互不干扰;但当线程1和线程2将同一个全局变量sum作为参数时,caculate就会运行异常,其实和不可重入版本的原因一样,都是因为两个线程使用了同一个全局变量,导致资源竞争。
void caculate(int a, int b, int* sum)
{*sum = a + b; // 线程1执行完这一步sum=1+2=3,此时线程2执行,sum=3+4=7int d = *sum + 1; //由于两个线程中,sum都指向全局变量sum,上面线程2执行后把线程1中计算的sum值覆盖了,所以线程1中的sum值是非预期的...
}// 全局变量
static int sum; //全局变量sum, 两个线程同时使用
int x1 = 1, x2 = 2;
// 假设线程1调用
caculate(x1, x2, &sum);
// 线程2调用
int x3 = 3, x4 = 4;
caculate(x3, x4, &sum);
4. 可重入且线程安全版本
QMutex mutex; //添加互斥锁后,即使两个线程传入同一个全局变量,计算d值时,也都是用的各自计算的sum值
void caculate(int a, int b, int* sum)
{mutex.lock(); //加锁*sum = a + b; //线程1执行完,sum=3int d = *sum + 1; //由于加了锁,所以计算d时,不会切换到线程2,用的还是线程1计算的sum值3mutex.unlock(); //解锁
}// 全局变量
static int sum;
// 假设线程1调用
int x1 = 1, x2 = 2;
caculate(x1, x2, &sum);
// 线程2调用
int x3 = 3, x4 = 4;
caculate(x1, x2, &sum);

