首页 / Unity3d / C#

读一读

上条笔记说的内存共享冲突后,可以使用锁来解决

通过锁住对象内存,只能允许同一时间只有一个线程可以访问,其他想要访问的线程排队等待

static void CallFunc(object obj) {
    Class1 o = obj as Class1;
    lock (o) {
        while (true) {
            o.Cooo();
        }
    }
}

使用lock关键字,申请o对象的内存访问,如果没有线程在访问,则锁住对象,进行里面的代码。如果对象已经被锁了,那么排队等待。


class Class1
{
    public int i = 5;
    public void Cooo() {
        this.i++;
        if (this.i == 5) {
            Console.WriteLine("我可能会被输出");
        }

        this.i = 5;
    }
}

static void CallFunc(object obj) {
    Class1 o = obj as Class1;
    while (true) {
        o.Cooo();
    }
}

Class1 c = new Class1();
Thread go1 = new Thread(CallFunc);
go1.Start(c);
Thread go2 = new Thread(CallFunc);
go2.Start(c);


此时,“我可能会被输出”真的会输出

从程序设计来看,这句话是不可能被输出的

但是,这里开启两个线程后,共享了这份内存

时间线变成了两条,不在是顺着,有可能在i++之后,另一个线程修改i=5,此时再到回到这个线程,判断i确实=5


static void First() {
    Console.WriteLine(2017);
    Console.WriteLine("First End");
}

static void Second(Task t) {
    Console.WriteLine("Second End");
}

static void Third(Task t) {
    Console.WriteLine("Third Start");
    Thread.Sleep(2000);
    Console.WriteLine("Third End");
}

Task t = new Task(First);
Task t2 = t.ContinueWith(Second);
Task t3 = t.ContinueWith(Third);
t.Start();

while (true) {
    Console.WriteLine(t.Status);
    Thread.Sleep(500);
}


使用new Task创建一个任务,通过这个任务的ContinueWith方法来创建连续任务,返回Task

就是在t任务完成后,t2和t3就开始异步执行

同理的,t2,t3也可以通过ContinueWith来创建他们的后续任务


static void test1() {
    Console.WriteLine("test1 1231321");
}

static void test2() {
    Console.WriteLine("test2");
}

//任务开启线程
Task tas = new Task(test1);
tas.Start();

TaskFactory tf = new TaskFactory();
Task tass = tf.StartNew(test2);


TaskFactory 是任务工厂(工厂模式)

通过StartNew()创建并开始一个任务


static void Thread3(object state) {
    Console.WriteLine("线程开始:"+Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(100);
    Console.WriteLine("线程结束");
}

ThreadPool.QueueUserWorkItem(Thread3);
ThreadPool.QueueUserWorkItem(Thread3);

直接通过ThreadPool静态类的QueueUserWorkItem方法传入要开启线程的方法,它内部会使用线程来执行

Thread.CurrentThread.ManagedThreadId获取当前线程id


一个应用程序最多只能有一个线程池,

通过ThreadPool静态类的QueueUserWorkItem()方法传入工作函数来排入线程池。

ThreadPool内部管理线程,是否开启新的线程还是使用旧的线程来完成(会检查有没有空闲的,没有先等待一下,再没有再创建新的)

线程池开启的线程,不受我们控制了。


class ThreadClass
{
    private int a;
    private int b;
    private int sum;

    public ThreadClass(int a,int b) {
        this.a = a;
        this.b = b;
    }

    public void sumThread() {
        this.sum = a + b;
    }

    public int getResult() {
        return this.sum;
    }
}

ThreadClass tc = new ThreadClass(100 , 150);
Thread tcTh = new Thread(tc.sumThread);
tcTh.Start();
tcTh.Join();//等待线程完成
Console.WriteLine(tc.getResult());


可以看出,Thread线程参数接受静态方法,也接受成员方法

tcTh.Join() 表示等待线程完成,再运行下面的代码


static void Thread2(object a) {
    int[] s = a as int[];
    int result = s[0] + s[1];
    Console.WriteLine("结果为:" + result);
}

using System.Threading;

Thread thread = new Thread(Thread2);
thread.Start(new int[] { 5, 8 });


通过Thread类开启一个线程,传递一个没有返回值的方法

该方法最多只能有一个参数并且类型为object的

Thread类在 System.Threading里面


static int Thread1(int a,int b) {
    Console.WriteLine("Thread1");
    return a + b;
}

static void CallBack(IAsyncResult ar) {
    Func<int, int, int> th = ar.AsyncState as Func<int, int, int>;
    int result = th.EndInvoke(ar);
    Console.WriteLine("结果为:" + result);
}

Func<int, int, int> th = Thread1;
th.BeginInvoke(9, 10, CallBack, th);


IAsyncResult ar为回调自动传参

通过AsyncState获取BeginInvoke方法最后一个参数传入的数据


static int Thread1(int a,int b) {
     Console.WriteLine("Thread1");
     return a + b;
}

Func<int, int, int> th = Thread1;
th.BeginInvoke(5, 3, ar =>
{
    int result = th.EndInvoke(ar);
    Console.WriteLine("结果:" + result);
}, null);

ar是IAsyncResult类型自动传给回调函数的

EndInvoke(ar) 获取线程(委托方法)的返回值