多线程问题,对初学者来说,会常常感到神秘。特别想知道它里面到底是怎么执行的;遇到问题时,又会觉得十分迷惑。
前面的例子,swap 语句串扰执行问题,实现了一个assign指令的解释器。现在就借用它的代码,用解释程序演示一下多线程是怎么执行的。
现在注意力集中到考虑,以swap(a,b):, swap(a,c):, 为蓝本的2个线程,每个线程各执行相应的swap代码10次。线程的数据结构是:
struct thread_proc {
int ecount;
int count;
struct assign **ins;
int n;
int cur;
};
其中,用ecount表示thread的任务是执行10次,count从 0计数,到ecount执行结束。ins照旧,存放swap(a,b):或swap(a,c):的指令。n是指令的长度。cur是thread当前执行到的位置。
线程初始化为各执行swap(a,b):或swap(a,c):10次:
struct assign *swap_ab_ins[3]= {
&all_assigns[0], &all_assigns[1], &all_assigns[2]
};
struct assign *swap_ac_ins[3]= {
&all_assigns[3], &all_assigns[4], &all_assigns[5]
};
struct thread_proc thread2[2]=
{
{10, 0, swap_ab_ins, 3, 0},
{10, 0, swap_ac_ins, 3, 0},
};
线程执行,每个片断执行1~3个线程指令:
void execute(struct thread_proc *t, int n)
{
int i;
int pos;
struct assign **a;
a = t->ins;
if(t==&thread2[0]) {
printf("swap(a,b):");
}
else {
printf("swap(a,c):");
}
for(i=0; i<n; i++) {
if(i) printf("\t");
pos = t->cur;
print_ins_nl(a[pos], 0);
*(a[pos]->left) = *(a[pos]->right);
printf("\t");
print_vars(&result); printf("\n");
t->cur++;
if(t->cur>=t->n) {
t->count++;
t->cur=0;
}
if(finish(t)) break;
}
}
调度程序,选择"下一个"需要执行的线程,交错执行每个线程:
struct thread_proc *run;
int finish(struct thread_proc *t)
{
return t->count>=t->ecount;
}
int sched()
{
struct thread_proc *next;
if(run== &thread2[0]) {
next= &thread2[1];
} else {
next= &thread2[0];
}
if(!finish(next)) {
run= next;
}
if(!finish(run)) return 1;
return 0;
}
当sched()选择的"下一个"线程已经finish,sched()就返回0。执行就结束了。就这些了。完整的代码贴上:
#include <stdio.h>
struct vars {
int a;
int b;
int c;
int t1;
int t2;
};
struct vars init= {'A', 'B', 'C', 'x', 'z'};
struct vars result;
struct assign {
int *left;
int *right;
};
struct assign all_assigns[] = {
{&result.t1,&result.a}, {&result.a, &result.b}, {&result.b,&result.t1},
{&result.t2,&result.a}, {&result.a, &result.c}, {&result.c,&result.t2},
};
void print_ins_nl(struct assign *a, int nl)
{
int i;
int *pi= a->left;
printf("\t(%d)\t", a- &all_assigns[0]);
for(i=0; i<2; i++) {
if(pi==&result.a) printf("a"); else
if(pi==&result.b) printf("b"); else
if(pi==&result.c) printf("c"); else
if(pi==&result.t1) printf("t1"); else
if(pi==&result.t2) printf("t2");
if(pi==a->left) {
printf("=");
pi=a->right;
}
}
if(nl)
printf(";\n");
else
printf(";");
}
void print_ins(struct assign *a)
{
print_ins_nl(a, 1);
}
void print_vars(struct vars *var)
{
printf("(%c, %c, %c, :%c, :%c)", var->a, var->b,var->c, var->t1, var->t2
);
}
struct thread_proc {
int ecount;
int count;
struct assign **ins;
int n;
int cur;
};
struct assign *swap_ab_ins[3]= {
&all_assigns[0], &all_assigns[1], &all_assigns[2]
};
struct assign *swap_ac_ins[3]= {
&all_assigns[3], &all_assigns[4], &all_assigns[5]
};
struct thread_proc thread2[2]=
{
{10, 0, swap_ab_ins, 3, 0},
{10, 0, swap_ac_ins, 3, 0},
};
struct thread_proc *run;
int finish(struct thread_proc *t)
{
return t->count>=t->ecount;
}
int sched()
{
struct thread_proc *next;
if(run== &thread2[0]) {
next= &thread2[1];
} else {
next= &thread2[0];
}
if(!finish(next)) {
run= next;
}
if(!finish(run)) return 1;
return 0;
}
void execute(struct thread_proc *t, int n)
{
int i;
int pos;
struct assign **a;
a = t->ins;
if(t==&thread2[0]) {
printf("swap(a,b):");
}
else {
printf("swap(a,c):");
}
for(i=0; i<n; i++) {
if(i) printf("\t");
pos = t->cur;
print_ins_nl(a[pos], 0);
*(a[pos]->left) = *(a[pos]->right);
printf("\t");
print_vars(&result); printf("\n");
t->cur++;
if(t->cur>=t->n) {
t->count++;
t->cur=0;
}
if(finish(t)) break;
}
}
extern "C" int rand();
int random()
{
return rand()%3+1;
}
int main()
{
int i;
printf("swap(a, b):\n");
for(i=0; i<3; i++) {
print_ins(&all_assigns[i]);
}
printf("swap(a, c):\n");
for(i=0; i<3; i++) {
print_ins(&all_assigns[i+3]);
}
printf("[execute]:\n");
result = init;
run = &thread2[0];
do {
execute(run, random());
}
while(sched());
return 0;
}
运行结果是交错执行2个线程的效果:
swap(a, b):
(0) t1=a;
(1) a=b;
(2) b=t1;
swap(a, c):
(3) t2=a;
(4) a=c;
(5) c=t2;
[execute]:
swap(a,b): (0) t1=a; (A, B, C, :A, :z)
swap(a,c): (3) t2=a; (A, B, C, :A, :A)
(4) a=c; (C, B, C, :A, :A)
(5) c=t2; (C, B, A, :A, :A)
swap(a,b): (1) a=b; (B, B, A, :A, :A)
swap(a,c): (3) t2=a; (B, B, A, :A, :B)
(4) a=c; (A, B, A, :A, :B)
(5) c=t2; (A, B, B, :A, :B)
swap(a,b): (2) b=t1; (A, A, B, :A, :B)
(0) t1=a; (A, A, B, :A, :B)
(1) a=b; (A, A, B, :A, :B)
swap(a,c): (3) t2=a; (A, A, B, :A, :A)
swap(a,b): (2) b=t1; (A, A, B, :A, :A)
swap(a,c): (4) a=c; (B, A, B, :A, :A)
(5) c=t2; (B, A, A, :A, :A)
swap(a,b): (0) t1=a; (B, A, A, :B, :A)
swap(a,c): (3) t2=a; (B, A, A, :B, :B)
(4) a=c; (A, A, A, :B, :B)
(5) c=t2; (A, A, B, :B, :B)
swap(a,b): (1) a=b; (A, A, B, :B, :B)
(2) b=t1; (A, B, B, :B, :B)
swap(a,c): (3) t2=a; (A, B, B, :B, :A)
swap(a,b): (0) t1=a; (A, B, B, :A, :A)
(1) a=b; (B, B, B, :A, :A)
(2) b=t1; (B, A, B, :A, :A)
swap(a,c): (4) a=c; (B, A, B, :A, :A)
swap(a,b): (0) t1=a; (B, A, B, :B, :A)
(1) a=b; (A, A, B, :B, :A)
(2) b=t1; (A, B, B, :B, :A)
swap(a,c): (5) c=t2; (A, B, A, :B, :A)
swap(a,b): (0) t1=a; (A, B, A, :A, :A)
(1) a=b; (B, B, A, :A, :A)
(2) b=t1; (B, A, A, :A, :A)
swap(a,c): (3) t2=a; (B, A, A, :A, :B)
swap(a,b): (0) t1=a; (B, A, A, :B, :B)
swap(a,c): (4) a=c; (A, A, A, :B, :B)
(5) c=t2; (A, A, B, :B, :B)
(3) t2=a; (A, A, B, :B, :A)
swap(a,b): (1) a=b; (A, A, B, :B, :A)
(2) b=t1; (A, B, B, :B, :A)
(0) t1=a; (A, B, B, :A, :A)
swap(a,c): (4) a=c; (B, B, B, :A, :A)
(5) c=t2; (B, B, A, :A, :A)
swap(a,b): (1) a=b; (B, B, A, :A, :A)
(2) b=t1; (B, A, A, :A, :A)
(0) t1=a; (B, A, A, :B, :A)
swap(a,c): (3) t2=a; (B, A, A, :B, :B)
(4) a=c; (A, A, A, :B, :B)
(5) c=t2; (A, A, B, :B, :B)
swap(a,b): (1) a=b; (A, A, B, :B, :B)
(2) b=t1; (A, B, B, :B, :B)
(0) t1=a; (A, B, B, :A, :B)
swap(a,c): (3) t2=a; (A, B, B, :A, :A)
(4) a=c; (B, B, B, :A, :A)
swap(a,b): (1) a=b; (B, B, B, :A, :A)
(2) b=t1; (B, A, B, :A, :A)
swap(a,c): (5) c=t2; (B, A, A, :A, :A)
swap(a,c): (3) t2=a; (B, A, A, :A, :B)
swap(a,c): (4) a=c; (A, A, A, :A, :B)
swap(a,c): (5) c=t2; (A, A, B, :A, :B)