用解释程序交错执行2个线程

多线程问题,对初学者来说,会常常感到神秘。特别想知道它里面到底是怎么执行的;遇到问题时,又会觉得十分迷惑。

前面的例子,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)

如果带互斥锁。互斥锁是处理器硬件和操作系统休眠/调度程序相互作用的特殊代码。解释程序中可用setjmp/longjmp来模拟。如果线程请求互斥锁遇到已加锁,须退出本次执行,回到sched转让处理机。带锁的程序修改之后如下:

#include <stdio.h>
#include <setjmp.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;
}

jmp_buf resched;
struct mutex {
        int stat;
} mutex;
void lock() {
        if(mutex.stat==0) {
                mutex.stat=1;
                return;
        }
        longjmp(resched, 1);
}
void unlock() { mutex.stat=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;
				if(pos==0) {
				        lock();
				}
                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) {
						unlock();
                        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];
		if(setjmp(resched)!=0) goto resched;
        do {
                execute(run, random());
                resched: ;
        }
        while(sched());
        return 0;
}

运行结果:

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):swap(a,b):    (1)     a=b;    (B, B, C, :A, :z)
swap(a,c):swap(a,b):    (2)     b=t1;   (B, A, C, :A, :z)
                (0)     t1=a;   (B, A, C, :B, :z)
                (1)     a=b;    (A, A, C, :B, :z)
swap(a,c):swap(a,b):    (2)     b=t1;   (A, B, C, :B, :z)
swap(a,c):      (3)     t2=a;   (A, B, C, :B, :A)
                (4)     a=c;    (C, B, C, :B, :A)
swap(a,b):swap(a,c):    (5)     c=t2;   (C, B, A, :B, :A)
                (3)     t2=a;   (C, B, A, :B, :C)
                (4)     a=c;    (A, B, A, :B, :C)
swap(a,b):swap(a,c):    (5)     c=t2;   (A, B, C, :B, :C)
swap(a,b):      (0)     t1=a;   (A, B, C, :A, :C)
                (1)     a=b;    (B, B, C, :A, :C)
                (2)     b=t1;   (B, A, C, :A, :C)
swap(a,c):      (3)     t2=a;   (B, A, C, :A, :B)
swap(a,b):swap(a,c):    (4)     a=c;    (C, A, C, :A, :B)
swap(a,b):swap(a,c):    (5)     c=t2;   (C, A, B, :A, :B)
swap(a,b):      (0)     t1=a;   (C, A, B, :C, :B)
swap(a,c):swap(a,b):    (1)     a=b;    (A, A, B, :C, :B)
                (2)     b=t1;   (A, C, B, :C, :B)
                (0)     t1=a;   (A, C, B, :A, :B)
swap(a,c):swap(a,b):    (1)     a=b;    (C, C, B, :A, :B)
                (2)     b=t1;   (C, A, B, :A, :B)
                (0)     t1=a;   (C, A, B, :C, :B)
swap(a,c):swap(a,b):    (1)     a=b;    (A, A, B, :C, :B)
                (2)     b=t1;   (A, C, B, :C, :B)
                (0)     t1=a;   (A, C, B, :A, :B)
swap(a,c):swap(a,b):    (1)     a=b;    (C, C, B, :A, :B)
                (2)     b=t1;   (C, A, B, :A, :B)
swap(a,c):      (3)     t2=a;   (C, A, B, :A, :C)
swap(a,b):swap(a,c):    (4)     a=c;    (B, A, B, :A, :C)
swap(a,b):swap(a,c):    (5)     c=t2;   (B, A, C, :A, :C)
swap(a,b):      (0)     t1=a;   (B, A, C, :B, :C)
                (1)     a=b;    (A, A, C, :B, :C)
                (2)     b=t1;   (A, B, C, :B, :C)
swap(a,c):      (3)     t2=a;   (A, B, C, :B, :A)
                (4)     a=c;    (C, B, C, :B, :A)
swap(a,b):swap(a,c):    (5)     c=t2;   (C, B, A, :B, :A)
swap(a,b):      (0)     t1=a;   (C, B, A, :C, :A)
                (1)     a=b;    (B, B, A, :C, :A)
                (2)     b=t1;   (B, C, A, :C, :A)
swap(a,c):      (3)     t2=a;   (B, C, A, :C, :B)
                (4)     a=c;    (A, C, A, :C, :B)
                (5)     c=t2;   (A, C, B, :C, :B)
swap(a,b):      (0)     t1=a;   (A, C, B, :A, :B)
                (1)     a=b;    (C, C, B, :A, :B)
                (2)     b=t1;   (C, A, B, :A, :B)
swap(a,c):      (3)     t2=a;   (C, A, B, :A, :C)
                (4)     a=c;    (B, A, B, :A, :C)
swap(a,c):      (5)     c=t2;   (B, A, C, :A, :C)
                (3)     t2=a;   (B, A, C, :A, :B)
                (4)     a=c;    (C, A, C, :A, :B)
swap(a,c):      (5)     c=t2;   (C, A, B, :A, :B)
swap(a,c):      (3)     t2=a;   (C, A, B, :A, :C)
swap(a,c):      (4)     a=c;    (B, A, B, :A, :C)
swap(a,c):      (5)     c=t2;   (B, A, C, :A, :C)
swap(a,c):      (3)     t2=a;   (B, A, C, :A, :B)
                (4)     a=c;    (C, A, C, :A, :B)
swap(a,c):      (5)     c=t2;   (C, A, B, :A, :B)

加锁之后,swap(a,b)和swap(a,c)串行执行。数据得到了保护。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值