using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
public class EventTest
{
private int value;
public delegate void NumManipulationHandler();
public event NumManipulationHandler ChangeNum;
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum();//事件被触发
}
else
{
Console.WriteLine("event not fire");
Console.ReadKey();//回车继续
}
}
public EventTest()
{
int n = 5;
SetValue(n);
}
public void SetValue(int n)
{
if (value != n)
{
value = n;
OnNumChanged();
}
}
}
public class subscribEvent
{
public void printf()
{
Console.WriteLine("event fire");
Console.ReadKey();//回车继续
}
}
public class MainClass
{
public static void Main1()
{
//EventTest e = new EventTest();//实例化对象,第一次没有触发事件
//subscribEvent v = new subscribEvent();//实例化对象
//e.ChangeNum += new EventTest.NumManipulationHandler(v.printf);//注册
//e.SetValue(7);
//e.SetValue(11);
//System.Threading.Thread t = new System.Threading.Thread(PrintNumbersWithDelay);
//t.Start();
//t.Join();
//PrintNumbers();
/*
在C#中,对于不需要考虑严格时序的任务,线程是一个很方便的东西
将没一个单独需要执行的事情都作为一个线程,在主函数中调用就可以了
新建一个项目之后,需要引入线程相关的命名空间,里面包含了线程相关的class的定义功能函数等内容
using System.Threading
先定义一个thread类型的变量,其中th是该线程的名字,如果需要对该线程进行操作,就是对变量th的操作
ThreadMethod则是该线程所执行的函数
Thread th = new Thread(ThreadMethod);//创建线程
线程函数内容如下,该函数是每隔500ms像控制台打印一次东西
一般用到线程的情况都是一个线程一致监听并处理一些事情,所以会有一个while(true),即永不退出
由于线程和主进程是一样,是一直在执行并且常驻内存的(一般的子函数都是在堆栈中运行,调用的时候就在堆栈中临时租借
一块地,函数执行完了再把那块地还给你,而static关键字就是说,系统啊你要给我在内存里专门开一块地放置我的代码块
我以后就是你的固定客户)所以线程函数也和主函数一样,需要加static关键字,并且是void类型的
当线程需要启动时(假设你这个线程是统计景区人流量的,作为主管的你在家睡大叫,然后请一个零时工来干活)
th.Start()//启动
当线程需要挂其实现在你亲戚来了你给她开个后门直接放进去,这个时候暂时不需要统计了,执行Suspend函数可以实现线程的挂起
th.Suspend
当线程需要继续开始时(亲戚都进去完了)执行Resume函数可以实现线程的继续执行
th.Resume();继续线程
当线程需要停止时(下班了)执行Absort函数可以实现线程的终止
th.Absort();//终止线程
*/
//在Main方法下面加入以下代码片段
Console.WriteLine("main start\r\n");
Thread th = new Thread(ThreadMethod);//创建线程
th.Start();//启动线程
for (int i = 0; i < 10; i++)
{
if (i==3) th.Suspend();
if (i==5) th.Resume();
if (i==7) th.Abort();
Console.WriteLine(i+"\r\n");
Thread.Sleep(1000);
}
Console.WriteLine("main end\r\n");
Console.ReadKey();
}
static void ThreadMethod()
{
while (true)
{
Console.WriteLine("thread\r\n");
Thread.Sleep(500);
}
}
static void PrintNumbers()
{
Console.WriteLine("Starting...");
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
}
static void PrintNumbersWithDelay()
{
Console.WriteLine("Starting...");
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine(i);
}
/*
当程序运行时,会创建一个线程,该线程会执行PrintNumbersWithDelay方法中的代码
然后会立即执行PrintNumbers方法。关键之处在于PrintNumbersWithDelay方法中加入了Thread.Sleep方法调用
这将导致线程执行该代码时,在打印任何数字之前会等待指定的时间(本例中是2秒钟)。当线程处于休眠状态时
它会占用尽可能少的CPU时间。结果我们会发现通常后运行的PrintNumbers方法中的代码比独立线程中的PrintNumbersWithDelay
方法中的代码先执行
1.4线程等待
本节将展示如何让程序等待另一个线程中的计算完成,然后在代码中使用该线程的计算结果。使用Thread.Sleep行不通,有i那位并不知道
执行计算需要花费的具体时间
工作原理
当程序运行时,启动了一个耗时较长的线程来打印数字,打印每个数字前要等待两秒
但我们在主程序中调用了t.Join方法,该方法允许我们等待直到线程t完成。当线程t完成时
主线程会继续运行。接组合该技术可以实现两个线程间同步执行步骤
第一个线程会等待另一个线程完成后在继续执行,第一个线程等待时是处于阻塞状态(正如1.3节中调用
Thread.Sleep方法一样)
编程中的模式是指针对既定问题的具体的标准的方案。通常,编程模式是人们总结的经验的结果
即分析常见的问题,并对这些问题提供方案
由于并行编程已经存在很长一堆时间,有很多不同的模式来编写并行的应用程序
设置有特殊的编程语言更加容易地编写特定并行算法。然而,这正是事情变得日益复杂的源头
在本书中,我将提供一个七点从而帮助你能够进一步学习并行编程
我们将回顾非常基础的但是非常有用的模式,这对于解决异步编程的很多常见的方案有帮助
首先是关于在多线程中使用共享状态的对象。我想强调你应当尽可能地避免使用它
我们在之前章节中已经讨论过了,当编写并行算法时共享状态是非常不好的方式,但在很多场合中
它又是不可避免的。我们将学习如何延迟一个对象的计算直到需要时才进行计算,以及如何在不同场景中
实现线程安全
接下来的两节将展示如何创建一个结构化的并行数据流。我们将回顾生产者、消费者模式
具体实例,其被成为并行管道(Parallel Pipeline)我们通过阻塞集合来实现它
然后看看微软提供的另一个并行编程库-TPL数据流(TPL DataFlow)是多么有用
我们将学习的最后一个模式是Map/Reduce模式。现代世界中,该名字可以指很多事情
一些人认为map/reduce不是针对任何问题的通用方式,而是大型的分布式的集群计算的实现
我们将找出该名称背后的含义,以及学习如何在小型的并行应用程序中使用该模式
10.2 实现惰性求值的共享状态
本节展示了如何编写一个具有惰性求值的线程安全的共享状态对象
10.2.1
*/
}
}
}