并发的三种层次
- 指令级
- 代码级
- 接口级
指令级
以汇编指令为单位进行并发, 结果与汇编指令的相对顺序有关
C++
int x = 0;
A:
{
x++;
}
B:
{
x++;
}
汇编
mov [x],0
A:
{
mov eax, [x] a1
inc eax a2
mov [x],eax a3
}
B:
{
mov eax, [x] b1
inc eax b2
mov [x],eax b3
}
x++ 分三步:
- 内存读数据到寄存器
- 寄存器数据自增
- 寄存器数据存回内存
不变量: x 在内存的值表示其自增的次数
操作序列: a1 b1 a2 b2 a3 b3 , 最终 x 在内存的值为 1, 与自增次数不符
操作序列所有可能情况
a1 a2 a3 和 b1 b2 b3 保证各自的顺序的前提下, 混合为一个操作序列共有 20 种情况
只有2种情况正确, 其余都错误
a1 a2 a3 b1 b2 b3 正确
a1 a2 b1 a3 b2 b3
a1 a2 b1 b2 a3 b3
a1 a2 b1 b2 b3 a3
a1 b1 a2 a3 b2 b3
a1 b1 a2 b2 a3 b3
a1 b1 a2 b2 b3 a3
a1 b1 b2 a2 a3 b3
a1 b1 b2 a2 b3 a3
a1 b1 b2 b3 a2 a3
b1 a1 a2 a3 b2 b3
b1 a1 a2 b2 a3 b3
b1 a1 a2 b2 b3 a3
b1 a1 b2 a2 a3 b3
b1 a1 b2 a2 b3 a3
b1 a1 b2 b3 a2 a3
b1 b2 a1 a2 a3 b3
b1 b2 a1 a2 b3 a3
b1 b2 a1 b3 a2 a3
b1 b2 b3 a1 a2 a3 正确
代码级
以高级语言代码为单位进行并发, 结果与代码的相对顺序有关
int x = 0;
A:
{
if(x == 0) a1
x++; a2
}
B:
{
if(x == 0) b1
x++; b2
}
操作序列共有 6 种情况:
a1 a2 b1 b2 正确
a1 b1 a2 b2
a1 b1 b2 a2
b1 a1 a2 b2
b1 a1 b2 a2
b1 b2 a1 a2 正确
2 种情况正确, 4 种情况错误
接口级
以接口为单位进行并发, 结果与接口的相对顺序有关
stack stk;
stk.push(0);
A:
{
if(stk.size()) a1
stk.pop(); a2
}
B:
{
if(stk.size()) b1
stk.pop(); b2
}
操作序列共有 6 种情况:
a1 a2 b1 b2 正确
a1 b1 a2 b2
a1 b1 b2 a2
b1 a1 a2 b2
b1 a1 b2 a2
b1 b2 a1 a2 正确
2 种情况正确, 4 种情况错误
验证方法
用穷举的方式将并发过程中可能出现所有情况列举出来
#include <iostream>
#include <vector>
using namespace std;
int cnt;
vector<string> a{"a1", "a2", "a3"}; // 过程 A 的操作序列
vector<string> b{"b1", "b2", "b3"}; // 过程 B 的操作序列
vector<string> path; // 并发后的操作序列
void dfs(int i, int j)
{
if(i + j == a.size() + b.size())
{
cnt++;
for(auto t : path)
cout << t << " ";
cout << endl;
return;
}
if(i < a.size())
{
path.push_back(a[i]);
dfs(i + 1, j);
path.pop_back();
}
if(j < b.size())
{
path.push_back(b[j]);
dfs(i, j + 1);
path.pop_back();
}
}
int main()
{
dfs(0, 0);
cout << cnt << endl;
}