您的位置:威尼斯官方网站 > 威尼斯正规官网 > 您将在组件中创建公共变量

您将在组件中创建公共变量

发布时间:2020-01-04 06:11编辑:威尼斯正规官网浏览(179)

    能够编写能何况进行三个任务的应用程序。此技巧(称为“多线程管理”或“自由线程管理”)是规划微型机密集型且须求客商输入的零件的强有力方法。计算薪金表消息的机件正是三个恐怕行使十二线程管理的构件示例。该构件能够在叁个线程上拍卖客户输入到数据库的数量,而在另二个线程上施行频仍利用计算机的薪俸表计算。通过在差别的线程上运营那些经过,客户无需等到计算机完结总结,就可以输入任何数据。在本演练中,将创立二个粗略的四线程组件,该器件能够何况举办多少个复杂总计。

    始建项目
    应用程序将囊括单个窗体和二个组件。客户将输入值并指示该器件初叶估量。然后,窗体将收到来自该零零件的值,将其出示在标签控件中。该器件将推行频仍利用项理器的忖度,并在产生后通知窗体。您将要组件中开创公共变量,用以保存从顾客分界面收到的值。同期,您还就要组件中贯彻部分主意,依据这几个变量的值实行计算。

    留意就算对于计算值的办法来说,函数日常更为可取,但不能在线程之间传递参数,也不可能重回值。有过多向线程提供值和从线程选择值的总结方法。在本演示中,将通过校勘公共变量将值再次来到到客商界面,当线程推行完毕后,使用事件来文告主程序。
    开创窗体

    创办新的“Windows 应用程序”项目。
    将应用程序命名字为 Calculations,并将 Form1.cs 重命名字为frmCalculations.cs。
    该窗体将用作应用程序的主客商分界面。

    双击设计器上的窗体以张开代码编辑器。在“编辑”菜单中,接受“查找和替换”,然后选取“替换”。使用“全部轮流”将 Form1 轮番为 frmCalculations。
    在“施工方案财富微处理器”中,右击“frmCalculations.cs”并精选“视图设计器”。设计器展开。
    向窗体中加多 5 个 Label 控件、4 个 Button 控件和 1 个 TextBox 控件。
    为那一个控件设置属性,如下所示:
    控件 名称 文本
    Label1 lblFactorial1 (空白)
    Label2 lblFactorial2 (空白)
    Label3 lblAddTwo (空白)
    Label4 lblRunLoops (空白)
    Label5 lblTotalCalculations (空白)
    Button1 btnFactorial1 Factorial
    Button2 btnFactorial2 Factorial - 1
    Button3 btnAddTwo Add Two
    Button4 btnRunLoops Run a Loop
    Textbox1 txtValue (空白)

    创建 Calculator 组件

    从“项目”菜单中选取“增添组件”。
    将构件命名称叫 Calculator。
    向 Calculator 组件增添公共变量

    为 Calculator 展开代码编辑器。
    加上创建公共变量的口舌,那么些变量用于将值从 frmCalculations 传递给各类线程。
    变量 varTotalCalculations 将保留该构件推行的计量总的数量的总共值,而其它变量将收受来自窗体的值。

    public int varAddTwo;
    public int varFact1;
    public int varFact2;
    public int varLoopValue;
    public double varTotalCalculations = 0;
    向 Calculator 组件增加方法和事件

    为事件表明委托,组件将采取那一个事件向窗体传递值。
    留意 纵然你将宣示 4 个事件,但由于内部的三个事件将全数相仿的签名,由此只需求创设 3 个委托。
    进而上一步输入的变量申明的江湖,键入下列代码:

    // This delegate will be invoked with two of your events.
    public delegate void FactorialCompleteHandler(double Factorial, double TotalCalculations);
    public delegate void AddTwoCompleteHandler(int Result, double TotalCalculations);
    public delegate void LoopCompleteHandler(double TotalCalculations, int Counter);
    扬言组件将用来与应用程序实行通讯的风浪。为促成此指标,紧接着上一步输入的代码的俗世,增多下列代码。
    public event FactorialCompleteHandler FactorialComplete;
    public event FactorialCompleteHandler FactorialMinusOneComplete;
    public event AddTwoCompleteHandler AddTwoComplete;
    public event LoopCompleteHandler LoopComplete;
    跟着上一步键入的代码的尘寰,键入下列代码:
    // This method will calculate the value of a number minus 1 factorial
    // (varFact2-1!).
    public void FactorialMinusOne()
    {
    double varTotalAsOfNow = 0;
    double varResult = 1;
    // Performs a factorial calculation on varFact2 - 1.
    for (int varX = 1; varX <= varFact2 - 1; varX++)
    {
    varResult *= varX;
    // Increments varTotalCalculations and keeps track of the current
    // total as of this instant.
    varTotalCalculations += 1;
    varTotalAsOfNow = varTotalCalculations;
    }
    // Signals that the method has completed, and communicates the
    // result and a value of total calculations performed up to this
    // point.
    FactorialMinusOneComplete(varResult, varTotalAsOfNow);
    }

    // This method will calculate the value of a number factorial.
    // (varFact1!)
    public void Factorial()
    {
    double varResult = 1;
    double varTotalAsOfNow = 0;
    for (int varX = 1; varX <= varFact1; varX++)
    {
    varResult *= varX;
    varTotalCalculations += 1;
    varTotalAsOfNow = varTotalCalculations;
    }
    FactorialComplete(varResult, varTotalAsOfNow);
    }

    // This method will add two to a number (varAddTwo+2).
    public void AddTwo()
    {
    double varTotalAsOfNow = 0;
    int varResult = varAddTwo + 2;
    varTotalCalculations += 1;
    varTotalAsOfNow = varTotalCalculations;
    AddTwoComplete(varResult, varTotalAsOfNow);
    }

    // This method will run a loop with a nested loop varLoopValue times.
    public void RunALoop()
    {
    int varX;
    double varTotalAsOfNow = 0;
    for (varX = 1; varX <= varLoopValue; varX++)
    {
    // This nested loop is added solely for the purpose of slowing down
    // the program and creating a processor-intensive application.
    for (int varY = 1; varY <= 500; varY++)
    {
    varTotalCalculations += 1;
    varTotalAsOfNow = varTotalCalculations;
    }
    }
    LoopComplete(varTotalAsOfNow, varLoopValue);
    }
    将客商输入传输到零器件
    下一步是向 frmCalculations 加多代码,以选取客商输入,以至从 Calculator 组件接收值和向它传输值。

    贯彻 frmCalculations 的前端功效

    在代码编辑器中开荒 frmCalculations。
    找到 public class frmCalculations 语句。紧接着 { 的江湖键入:
    Calculator Calculator1;
    找到构造函数。紧接着 } 以前,增添以下行:
    // Creates a new instance of Calculator.
    Calculator1 = new Calculator();
    在设计器中单击每一种开关,为每种控件的单击事件处理程序生成代码大纲,并加上代码以创办那些管理程序。
    姣好后,单击事件管理程序应该贴近于以下情势:

    private void btnFactorial1_Click(object sender, System.EventArgs e)
    // Passes the value typed in the txtValue to Calculator.varFact1.
    {
    Calculator1.varFact1 = int.Parse(txtValue.Text);
    // Disables the btnFactorial1 until this calculation is complete.
    btnFactorial1.Enabled = false;
    Calculator1.Factorial();
    }

    private void btnFactorial2_Click(object sender, System.EventArgs e)
    {
    Calculator1.varFact2 = int.Parse(txtValue.Text);
    btnFactorial2.Enabled = false;
    Calculator1.FactorialMinusOne();
    }
    private void btnAddTwo_Click(object sender, System.EventArgs e)
    {
    Calculator1.varAddTwo = int.Parse(txtValue.Text);
    btnAddTwo.Enabled = false;
    Calculator1.AddTwo();
    }
    private void btnRunLoops_Click(object sender, System.EventArgs e)
    {
    Calculator1.varLoopValue = int.Parse(txtValue.Text);
    btnRunLoops.Enabled = false;
    // Lets the user know that a loop is running
    lblRunLoops.Text = "Looping";
    Calculator1.RunALoop();
    }
    在上一步增加的代码的花天酒地,键入以下代码以拍卖窗体将从 Calculator1 接纳的风浪:
    protected void FactorialHandler(double Value, double Calculations)
    // Displays the returned value in the appropriate label.
    {
    lblFactorial1.Text = Value.ToString();
    // Re-enables the button so it can be used again.
    btnFactorial1.Enabled = true;
    // Updates the label that displays the total calculations performed
    lblTotalCalculations.Text = "TotalCalculations are " +
    Calculations.ToString();
    }

    protected void FactorialMinusHandler(double Value, double Calculations)
    {
    lblFactorial2.Text = Value.ToString();
    btnFactorial2.Enabled = true;
    lblTotalCalculations.Text = "TotalCalculations are " +
    Calculations.ToString();
    }

    protected void AddTwoHandler(int Value, double Calculations)
    {
    lblAddTwo.Text = Value.ToString();
    btnAddTwo.Enabled = true;
    lblTotalCalculations.Text = "TotalCalculations are " +
    Calculations.ToString();
    }

    protected void LoopDoneHandler(double Calculations, int Count)
    {
    btnRunLoops.Enabled = true;
    lblRunLoops.Text = Count.ToString();
    lblTotalCalculations.Text = "TotalCalculations are " +
    Calculations.ToString();
    }
    在 frmCalculations 的构造函数中,紧挨在 } 以前增加下列代码,以处理窗体将从 Calculator1 选择的自定义事件:
    Calculator1.FactorialComplete += new
    Calculator.FactorialCompleteHandler(this.FactorialHandler);
    Calculator1.FactorialMinusOneComplete += new
    Calculator.FactorialCompleteHandler(this.FactorialMinusHandler);
    Calculator1.AddTwoComplete += new
    Calculator.AddTwoCompleteHandler(this.AddTwoHandler);
    Calculator1.LoopComplete += new
    Calculator.LoopCompleteHandler(this.LoopDoneHandler);
    测量试验应用程序
    至今项目早已创办达成,该项目将能够实施多少个复杂计算的机件与窗体结合在联名。就算还未落到实处二十四线程处理效果,但在后续以前应该对项目开展测验,以表明它的作用。

    测量试验项目

    从“调节和测验”菜单中选拔“运营”。
    应用程序运转并显示 frmCalculations。

    在文本框中键入 4,然后单击标识为“加多八个”的按键。
    在开关下方的价签中应当显得数字“6”,在 lblTotalCalculations 中应有出示“Total Calculations are 1”。

    今昔单击标识为“阶乘 - 1”的开关。
    该按键的世间应展现数字“6”,而 lblTotalCalculations 中以往应展现“Total Calculations are 4”。

    将文本框中的值纠正为 20,然后单击标志为“阶乘”的开关。
    该开关的世间展现数字“2.43290二零一零17664E+18”,而 lblTotalCalculations 中未来突显为“Total Calculations are 24”。

    将文本框中的值修改为 50000,然后单击标识为“运营循环”的开关。
    在乎,在这里开关重新启用前有二个短暂可是总之的区间。此开关下的标签应体现“50000”,而总的计算次数字呈现示为“25000024”。

    将文本框中的值校勘为 5000000 并单击标志为“运营循环”的按键,紧接着单击标识为“增添七个”的按键。再次单击它。
    直至循环已经完毕,该开关以至窗体上的别的控件才有响应。

    后生可畏经程序只运维单个施行线程,则附近上述示范的数次使用微型机的预计倾向于占用该程序,直到总括已经变成。在下生龙活虎节中,您将向应用程序加多三十二线程管理效果,以便贰遍能够运作多少个线程。

    增加多线程处理效果
    上边的身先士卒演示了只运营单个实践线程的应用程序的界定。在下风华正茂节,您将接收Thread 类对象向组件增添多少个施行线程。

    添加 Threads 子例程

    在代码编辑器中开发 Calculator.cs。
    在代码顶上部分周边,找到类注明,紧接着 { 的江湖,键入下列代码:
    // Declares the variables you will use to hold your thread objects.
    public System.Threading.Thread FactorialThread;
    public System.Threading.Thread FactorialMinusOneThread;
    public System.Threading.Thread AddTwoThread;
    public System.Threading.Thread LoopThread;
    在代码底部紧接着类评释最终早先,增加以下方式:
    public void ChooseThreads(int threadNumber)
    {
    // Determines which thread to start based on the value it receives.
    switch(threadNumber)
    {
    case 1:
    // Sets the thread using the AddressOf the subroutine where
    // the thread will start.
    FactorialThread = new System.Threading.Thread(new
    System.Threading.ThreadStart(this.Factorial));
    // Starts the thread.
    FactorialThread.Start();
    break;
    case 2:
    FactorialMinusOneThread = new
    System.Threading.Thread(new
    System.Threading.ThreadStart(this.FactorialMinusOne));
    FactorialMinusOneThread.Start();
    break;
    case 3:
    AddTwoThread = new System.Threading.Thread(new
    System.Threading.ThreadStart(this.AddTwo));
    AddTwoThread.Start();
    break;
    case 4:
    LoopThread = new System.Threading.Thread(new
    System.Threading.ThreadStart(this.RunALoop));
    LoopThread.Start();
    break;
    }
    }
    当实例化 Thread 对象时,它供给一个 ThreadStart 对象格局的参数。ThreadStart 对象是多个照准领头线程的章程之处的信托。ThreadStart 对象不可能选择参数或许传递值,由此只能表示 void 方法。刚才完成的 ChooseThreads 方法将从调用它的主次接收三个值,并行使该值来规定要开动的伏贴线程。

    向 frmCalculations 增多适当的代码

    在代码编辑器中开采 frmCalculations.cs 文件,然后找到 protected void btnFactorial1_Click。
    评释掉直接调用 Calculator1.Factorial1 方法的行,如下所示:
    // Calculator1.Factorial()
    增加下列行,以调用 Calculator1.ChooseThreads 办法:
    // Passes the value 1 to Calculator1, thus directing it to start the
    // correct thread.
    Calculator1.ChooseThreads(1);
    对其他 button_click 子例程作相同的改动。
    只顾 一定要为 Threads 参数包含适当的值。
    姣好后,代码看起来应当周围以下方式:

    protected void btnFactorial1_Click(object sender, System.EventArgs e)
    // Passes the value typed in the txtValue to Calculator.varFact1
    {
    Calculator1.varFact1 = int.Parse(txtValue.Text);
    // Disables the btnFactorial1 until this calculation is complete
    btnFactorial1.Enabled = false;
    // Calculator1.Factorial();
    Calculator1.ChooseThreads(1);
    }

    protected void btnFactorial2_Click(object sender, System.EventArgs e)
    {
    Calculator1.varFact2 = int.Parse(txtValue.Text);
    btnFactorial2.Enabled = false;
    // Calculator1.FactorialMinusOne();
    Calculator1.ChooseThreads(2);
    }
    protected void btnAddTwo_Click(object sender, System.EventArgs e)
    {
    Calculator1.varAddTwo = int.Parse(txtValue.Text);
    btnAddTwo.Enabled = false;
    // Calculator1.AddTwo();
    Calculator1.ChooseThreads(3);
    }

    protected void btnRunLoops_Click(object sender, System.EventArgs e)
    {
    Calculator1.varLoopValue = int.Parse(txtValue.Text);
    btnRunLoops.Enabled = false;
    // Lets the user know that a loop is running
    lblRunLoops.Text = "Looping";
    // Calculator1.RunALoop();
    Calculator1.ChooseThreads(4);
    }
    封送管理对控件的调用
    于今将加速窗体上的显得更新。鉴于控件总是由主试行线程全部,附属线程中对控件的别的调用都急需“封送管理”调用。封送管理是跨线程边界移动调用的一言一动,须求花费大量的能源。为了使供给发出的封送管理量减到起码,并确认保障以线程安全格局管理调用,应运用 Control.BeginInvoke 方法来调用主施行线程上的点子,进而使必需发生的跨线程边界的封送管理量减到起码。当调用操作控件的法门时,这种调用特别供给。有关详细新闻,请参见从线程操作控件。

    创办控件调用过程

    为 frmCalculations 展开代码编辑器。在宣称部分,增加下列代码:
    public delegate void FHandler(double Value, double Calculations);
    public delegate void A2Handler(int Value, double Calculations);
    public delegate void LDHandler(double Calculations, int Count);
    Invoke 和 BeginInvoke 供给将相符措施的信托作为参数。那一个代码行注明后生可畏(WissuState of Qatar些寄托签字,这个署老马被 BeginInvoke 用于调用适当的不二诀窍。

    在代码中增多下列空方法。
    public void FactHandler(double Value, double Calculations)
    {
    }
    public void Fact1Handler(double Value, double Calculations)
    {
    }
    public void Add2Handler(int Value, double Calculations)
    {
    }
    public void LDoneHandler(double Calculations, int Count)
    {
    }
    在“编辑”菜单中,使用“剪切”和“粘贴”,从 FactorialHandler 方法中剪切全数代码,并将其粘贴到 FactHandler 中。
    对 FactorialMinusHandler 和 Fact1Handler、AddTwoHandler 和 Add2Handler 以至 LoopDoneHandler 和 LDoneHandler 重复上边包车型客车步骤。
    实现后,在 FactorialHandler、Factorial1Handler、AddTwoHandler 和 LoopDoneHandler 中应有未有剩余代码,并且它们曾经富含的具有代码应该已经移动到符合的新办法中。

    调用 BeginInvoke 方法以异步调用这一个方法。能够从窗体 (thisState of Qatar恐怕窗体上的别的控件调用 BeginInvoke。
    变成后,代码看起来应当相近以下方式:

    protected void FactorialHandler(double Value, double Calculations)
    {
    // BeginInvoke causes asynchronous execution to begin at the address
    // specified by the delegate. Simply put, it transfers execution of
    // this method back to the main thread. Any parameters required by
    // the method contained at the delegate are wrapped in an object and
    // passed.
    this.BeginInvoke(new FHandler(FactHandler), new Object[]
    {Value, Calculations});
    }
    protected void FactorialMinusHandler(double Value, double Calculations)
    {
    this.BeginInvoke(new FHandler(Fact1Handler), new Object []
    {Value, Calculations});
    }

    protected void AddTwoHandler(int Value, double Calculations)
    {
    this.BeginInvoke(new A2Handler(Add2Handler), new Object[]
    {Value, Calculations});
    }

    protected void LoopDoneHandler(double Calculations, int Count)
    {
    this.BeginInvoke(new LDHandler(LDoneHandler), new Object[]
    {Calculations, Count});
    }
    看起来就像是事件管理程序仅仅是对下叁个措施开展调用。实际上,该事件管理程序实现了在主操作线程上调用方法。这种办法可节约跨线程边界的调用,并使八线程应用程序可以使得运营而不用忧虑产生死锁。有关在十二线程情况下利用控件的详细音信,请参见从线程操作控件。

    保存您的工作。
    从“调节和测量试验”菜单中选取“运营”,测量检验该解决方案。
    在文本框内键入 10000000 并单击“运营循环”。
    此开关下方的价签中显得“Looping”。运维这些轮回应该占有相当长日子。假如它形成得太快,请相应地调动该数字的轻重。

    接连几天来地急速单击仍在启用的多个按键。您会发觉装有开关都响应您的输入。在“Add Two”下方的价签应该首先个展现结果。结果稍后将体现在阶乘按键下方的标签中。猜测那个结果会Infiniti大,因为 10,000,000 的阶乘重临的数字对于双精度变量来说太大,以至超过了它蕴含的约束。最后,再过片刻,结果将赶回到“运转循环”开关下方。
    正如刚刚观望到的,在多个单身的线程上还要施行四组独立的测算。客商分界面保持对输入的响应,并在每一种线程完成后归来结果。

    和谐线程
    有资历的三十二线程应用程序客户恐怕会意识已键入的代码中设有细微破绽。从 Calculator.cs 中每一种试行总括的子例程中撤回以下代码行:

    varTotalCalculations += 1;
    varTotalAsOfNow = varTotalCalculations;
    这两行代码递增公共变量 varTotalCalculations 并将某个变量 varTotalAsOfNow 设为此值。然后,该值被重返给 frmCalculations,并出示在标签控件中。但重返的值不易吧?假若唯有单个试行线程在运营,则答案由此可以知道是科学的。可是假如有八个线程在运作,答案则变得不太分明。每一个线程都负有依次增加变量 varTotalCalculations 的力量。有希望现身如此的事态:在三个线程依次增加该变量之后,但在它将该值复制到 varTotalAsOfNow 以前,另三个线程只怕通过递增该变量而退换它的值。那将变成有十分的大恐怕每种线程实际上在告诉不允许确的结果。Visual C# 提供 lock 语句语句以允许线程的一同,进而保障每个线程始终重返准确的结果。lock 的语法如下所示:

    lock(AnObject)
    {
    // Insert code that affects the object.
    // Insert more code that affects the object.
    // Insert more code that affects the object.
    // Release the lock.
    }
    输入 lock 块后,在钦赐的线程对所商量的靶子具有专项使用锁早前,对点名表明式的实施一贯被梗塞。在上头展现的演示中,对 AnObject 的进行处于锁定状态。必需对回到引用的对象(而非再次来到值的对象)使用 lock。然后,推行以块的方式继续张开,而不会遭到任何线程的搅动。作为四个单元实践的话语集称为“原子”。当蒙受} 时,表明式将被假释,线程可三番五次健康干活。

    将 lock 语句增加到应用程序

    在代码编辑器中开发 Calculator.cs。
    找到下列代码的各个实例:
    varTotalCalculations += 1;
    varTotalAsOfNow = varTotalCalculations;
    相应有此代码的多个实例,各类总括情势中有叁个。

    改正此代码,使其出示为如下格局:
    lock(this)
    {
    varTotalCalculations += 1;
    varTotalAsOfNow = varTotalCalculations;
    }
    保留专门的工作,并按上例所示实行测量检验。
    您只怕注意到对程序质量的细微影响。那是因为当组件得到排他锁后,线程的施行截止。尽管它保障了不易,但这种措施抵消了二十四线程带给的一点品质优点。应该认真盘算锁定线程的须求性,而且仅当相对少不了时才予以兑现。

    本文由威尼斯官方网站发布于威尼斯正规官网,转载请注明出处:您将在组件中创建公共变量

    关键词:

上一篇:把Doc文档转换成rtf格式 [C#]

下一篇:没有了