线程学习笔记2

对于文章里面碰到的问题,可能也是我学习1当中出现的问题,新开的线程不管委托与否都在同一个线程里面,所以新线程运行的时候,主窗体也会停住,后来想在新线程中打开窗体的思路来处理,结果碰到下面文章的问题,在多方面的查找和学习后发现有一个办法可以解决它,希望对大家有帮助。

  private void button7_Click(object sender, EventArgs e)
        {
            Thread thread2 = new Thread(threadPro);//创建新线程
            thread2.Start();
        }

        public void threadPro()
        {
            Application.Run(new Form10());  //在新线程中用Application Run的方法打开新窗体
        }

        private void Exit_Click(object sender, EventArgs e)
        {
            //Application.Exit();
            Process.GetCurrentProcess().Kill(); //强制关闭所有进程,用这个代码之前一定要处理完程序正常结束应该保存的数据以及其他操作..
        }

  

参考下面的文章

最近做个Winform程序,就避免不到多窗体的应用,我在着里面自然也就产生了许多疑惑。首先,我们们在主窗体中点击一个按钮打开一个新窗体时,这个新窗体是否是一个新的线程中打开的呢?于是做个试验测试代码如下:

Form.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Test
{
    public partial class Form1 : Form
    {
        public Form2 f2;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            textBox1.Text = threadId.ToString(); //将主线程ID显示在文本框中
            f2 = new Form2();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            f2.Show();//显示Form2
        }
    }
}

  

Form2.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Test
{
    public partial class Form2 : Form
    {
        int i = 1;
        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());//弹出显示当前线程
        }
    }
}

  

运行结果:

很明显,都是在10号线程中运行的,但是现在有个问题出现了,假如,我们在Form1中读一个文本文件的同时Form2中对此文本文件进行写操作,那会冲突吗?这个还有待做实验验证了,在此省略了。

接下在线程中打开Form2

Form1.cs代码如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Test
{
    public partial class Form1 : Form
    {
        public Form2 f2;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            textBox1.Text = threadId.ToString(); //将主线程ID显示在文本框中
            f2 = new Form2();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread2 = new Thread(threadPro);//创建新线程
            thread2.Start();
        }
        public void threadPro()
        {
            f2.Show();
        }
    }
}

 

Form2.cs的代码不变

运行程序结果如下:

可以看到,两个窗体现在在不同的线程中了,但是我们点击确定后Form2窗体总是一闪而过就没有了,这是什么原因呢?这是因为在线程中建的窗体,所有的资源都是属于这个线程的,所以当这个线程结束后,它的资源也被回收了,当然C#也就自动把窗体给关闭了。

这里就需要对Form1.cs就行如下修改:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            textBox1.Text = threadId.ToString(); //将主线程ID显示在文本框中
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread2 = new Thread(threadPro);//创建新线程
            thread2.Start();
        }
        public void threadPro()
        {
             MethodInvoker MethInvo = new MethodInvoker(ShowForm2);
             BeginInvoke(MethInvo);
        }
        public void ShowForm2()
        {
            Form2 f2 = new Form2();
            f2.Show();
        }
    }
}

  

Form2代码不变,运行结果如下:

点击确定后Form2出现了,也不闪了,但是我们都看到一个问题,那就是两个窗体的在一个线程中,我们不是新建了一个线程吗?这是怎么回事?我的理解是代码中的MethodInvoker其实相当于一个委托,把它作为参数传递给BeginInvoke(MethInvo);执行,而BeginInvoke方法是在Control的线程上执行的,也就是我们平时所说的UI线程,也就是我们的主线程所以就解释了为什么都是10, 那如果我们想不在一个线程中怎么办呢?我能力不够,实在不知道,麻烦知道的告诉一声。

我们再对上面的程序进行扩展,那么就会解决一个问题,那就是子线程修改主线程的控件属性的问题。我们首先来看这个问题的存在如下

继续修改Form1.cs的代码,将我们创建的线程ID显示在Form1的第二个文本框中代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            textBox1.Text = threadId.ToString(); //将主线程ID显示在文本框中
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread2 = new Thread(threadPro);//创建新线程
            thread2.Start();
        }
        public void threadPro()
        {
            textBox2.Text = Thread.CurrentThread.ManagedThreadId.ToString();
             MethodInvoker MethInvo = new MethodInvoker(ShowForm2);
             BeginInvoke(MethInvo);
        }
        public void ShowForm2()
        {
            Form2 f2 = new Form2();
            f2.Show();
        }
    }
}

  

运行程序,点击按钮1,会报错如下:

原来是不能跨线程调用Window窗体控件;很简单我们将textBox2.Text = Thread.CurrentThread.ManagedThreadId.ToString();一道ShowForm2()函数中就能解决了,那这个提供了一个思路,那就是跨线程修改窗体属性通过委托就能实现了,我想是这样的吧,可能由于我能力不足只能作此简单分析,不足之处往指正。

 

时间: 2024-10-23 01:59:15

线程学习笔记2的相关文章

Java线程学习笔记(二) 线程的异常捕捉

线程异常的捕捉: 正常的情况下,我们在main()方法里是捕捉不到线程的异常的,例如以下代码: public class ExceptionThread implements Runnable{ @Override public void run() { throw new NullPointerException(); } public static void main(String[] args) { ExecutorService executorService = Executors.n

Java线程学习笔记(一)

一.线程的创建方式: 老掉牙的话题了,继承 java.lang.Thread父类或者实现Runnalbe接口,这里就提一句: class Thread implements Runnable Thread也是继承了Runnable接口的,Runnable才是大哥. 重写run(),run()里放的都是具体的业务,包括对线程的具体操作. class Thread1 implements Runnable { int i; Thread1(int i) { this.i = i; } @Overri

【转】linux 用户线程、LWP、内核线程学习笔记

[好文转发---linux 用户线程.LWP.内核线程学习笔记] 在现代操作系统中,进程支持多线程.进程是资源管理的最小单元:而线程是程序执行的最小单元.一个进程的组成实体可以分为两大部分:线程集合资源集.进程中的线程是动态的对象:代表了进程指令的执行.资源,包括地址空间.打开的文件.用户信息等等,由进程内的线程共享. 线程有自己的私有数据:程序计数器,栈空间以及寄存器. Why Thread?(传统单线程进程的缺点) 1. 现实中有很多需要并发处理的任务,如数据库的服务器端.网络服务器.大容量

线程学习笔记

1.什么是线程? 老师说过学好操作系统(Operating System)最重要的三个概念就是文件.虚存和进程了.之前已经学习过进程,因此对于线程的概念就比较好理解了. 进程是一个执行实体,操作系统是以进程为单位分配资源.在一个执行空间内可以用多个小型进程并发来完成不同的任务,这种小型的进程称之为线程.进程是一个比较大的概念,线程是一个比较具体化的小的概念,比如一个进程需要完成这样一个任务,读出用户收到的数据,将这些数据进行排序,再将这些数据输出,这是一个进程要完成的任务,这个进程中可以有三个线

线程学习笔记(二)

5.终止线程 线程退出的方式有3种 1.线程体函数执行结束,用 pthread_create() 函数创建一个新线程的时候会执行一个函数,这个函数就是线程体函数,如果该函数执行完毕,那么线程退出,类似于住进程的 main() 函数返回. 2.线程被另一个线程取消.这种方法类似于一个进程被另一个进程调用kill()函数杀死. 3.线程自行退出,类似于线程调用一个 exit() 函数. Linux系统中使用 pthread_exit(void *rval_ptr) 函数终止线程: 头文件:  #in

线程学习笔记(EventWaitHandler)AutoResetEvent的使用

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication46 { class TwoWaySignaling { //事件等待句柄 static EventWaitHandle _ready = new AutoRese

线程学习笔记 等待句柄和线程池(摘自https://blog.gkarch.com/threading/part2.html#manualresetevent)

//如果你的应用有很多线程,这些线程大部分时间都在阻塞,那么可以通过调用ThreadPool.RegisterWaitForSingleObject来减少资源消耗.这个方法接受一个委托,它会在向等待句柄发信号时执行.当处于等待状态时,它不会浪费线程资源: static ManualResetEvent _starter = new ManualResetEvent (false); public static void Main() { RegisteredWaitHandle reg = Th

lua协程----ngx-lua线程学习笔记

--[[ - @desc lua数据输出 - @param string 字符串 - return string --]] function dump(v) if not __dump then function __dump(v, t, p) local k = p or ""; if type(v) ~= "table" then table.insert(t, k .. " : " .. tostring(v)); else for key

Java线程学习笔记(两) 线程异常处理

线程捕获异常: 情况下,我们在main()方法里是捕捉不到线程的异常的,比例如以下面代码: public class ExceptionThread implements Runnable{ @Override public void run() { throw new NullPointerException(); } public static void main(String[] args) { ExecutorService executorService = Executors.new