首页 > 编程语言 >C# 线程---Thread1

C# 线程---Thread1

时间:2024-10-11 17:32:27浏览次数:1  
标签:Thread C# void --- static 线程 WriteLine new

 

1. thread 不带参数 (Main和Thread都在同步处理)(注意using static 和System.Console的使用)

using static System.Console;

namespace Recipe1
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t = new Thread(PrintNumber);
            t.Start();
            PrintNumber();
            Read();
        }
        static void PrintNumber()
        {
            WriteLine("Starting...");
            for (int i = 1; i < 10; i++)
            {
                WriteLine( i);
                Thread.Sleep(100);
            }
        }
    }
}
View Code

2. 暂停(休眠)线程,展示如何让一个线程等待一段时间而不用消耗操作系统资源,虽然先启动,但还是后运行。(sleep当线程处于休眠状态时,它会占用尽可能少的CPU时间)

class Program
    {
        static void Main(string[] args)
        {
            Thread t = new Thread(PrintNumbersWithDelay);
            t.Start();
            PrintNumbers();
        }

        static void PrintNumbers()
        {
            WriteLine("Starting PrintNumbers...");
            for (int i = 1; i < 10; i++)
            {
                WriteLine("PrintNumbers"+i);
            }
        }

        static void PrintNumbersWithDelay()
        {
            WriteLine("Starting PrintNumbersWithDelay...");
            for (int i = 1; i < 10; i++)
            {
                Sleep(TimeSpan.FromSeconds(2));
                WriteLine("PrintNumbersWithDelay "+i);
            }
        }
    }
View Code

 3. 等待线程完成,再往下走(t.Join() ,主线程处于阻塞状态(啥也不干),等待t这个线程完成,当线程t完成 时,主程序会继续运行

class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Starting program...");
            Thread t = new Thread(PrintNumbersWithDelay);
            t.Start();
            t.Join();
            WriteLine("Thread completed");
        }

        static void PrintNumbersWithDelay()
        {
            WriteLine("Starting...");
            for (int i = 1; i < 10; i++)
            {
                Sleep(TimeSpan.FromSeconds(2));
                WriteLine(i);
            }
        }
    }
View Code

4. 线程中途中止(t.Start();Sleep(TimeSpan.FromSeconds(6));t.Abort(); 我们等待6秒后对线程调用了 t.Abort方法 这给线程注入了 ThreadAbortException方法,导致线程被终结。这非常危险,因为该异常可 以在任何时刻发生并可能彻底摧毁应用程序;另外,使用该技术也不一定总能终止线程。目 标线程可以通过处理该异常并调用Thread.ResetAbort方法来拒绝被终止因此并不推荐使用 Abort方法来关闭线程°可优先使用一些其他方法.比如提供一个CancellationToken方法来 取消线程的执行

class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Starting program...");
            Thread t = new Thread(PrintNumbersWithDelay);
            t.Start();
            Sleep(TimeSpan.FromSeconds(6));
            t.Abort();
            WriteLine("A thread has been aborted");
        }

        static void PrintNumbersWithDelay()
        {
            WriteLine("Starting...");
            for (int i = 1; i < 10; i++)
            {
                Sleep(TimeSpan.FromSeconds(2));
                WriteLine(i);
            }
        }
    }
View Code

5. 描述一个线程可能会有哪些状态.获取线程是否已经启动或是否处于阻塞状态等(状态位于Thread对象的ThreadState属性中 ThreadState属性是一个C#枚举对象)

 1 static void Main(string[] args)
 2         {
 3             WriteLine("Main Starting program...");
 4             Thread t = new Thread(PrintNumbersWithStatus);
 5             Thread t2 = new Thread(DoNothing);
 6             WriteLine("PrintNumbersWithStatus:"+t.ThreadState.ToString());
 7             t2.Start();
 8             t.Start();
 9             for (int i = 1; i < 30; i++)
10             {
11                 WriteLine("PrintNumbersWithStatus:"+t.ThreadState.ToString());
12             }
13             Sleep(TimeSpan.FromSeconds(6));
14             t.Abort();
15             WriteLine("PrintNumbersWithStatus thread has been aborted");
16             WriteLine("PrintNumbersWithStatus:"+t.ThreadState.ToString());
17             WriteLine("DoNothing:"+t2.ThreadState.ToString());
18             Read();
19         }
20 
21         static void DoNothing()
22         {
23             Sleep(TimeSpan.FromSeconds(2));
24         }
25 
26         static void PrintNumbersWithStatus()
27         {
28             WriteLine("PrintNumbersWithStatus Starting...");
29             WriteLine("PrintNumbersWithStatus"+CurrentThread.ThreadState.ToString());
30             for (int i = 1; i < 10; i++)
31             {
32                 Sleep(TimeSpan.FromSeconds(2));
33                 WriteLine("PrintNumbersWithStatus "+i);
34             }
35         }
线程各阶段状态

 

 6. 线程优先级(线程优先级决定了该线程可占用多少 CPU时间)

如果拥有一个 以上的计算核心,将在两秒钟内得到初步结果,两个值应该很接近〉然而,如果有其他程序占用了所有的CPU核心运行负载,CPU核心大部分时间在运行高优先级的线程,只留给剩下的线程很少的时间来 运行,为了模拟该情形,我们设置了 ProcessorAffinity选项,止操作系统将所有的线程运 行在单个CPU核心(第一个核心)上。

class Program
    {
        static void Main(string[] args)
        {
            WriteLine($"Current thread priority: {CurrentThread.Priority}");
            WriteLine("Running on all cores available");
            RunThreads();
            Sleep(TimeSpan.FromSeconds(2));
            WriteLine("Running on a single core");
            GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
            RunThreads();
        }

        static void RunThreads()
        {
            var sample = new ThreadSample();

            var threadOne = new Thread(sample.CountNumbers);
            threadOne.Name = "ThreadOne";
            var threadTwo = new Thread(sample.CountNumbers);
            threadTwo.Name = "ThreadTwo";

            threadOne.Priority = ThreadPriority.Highest;
            threadTwo.Priority = ThreadPriority.Lowest;
            threadOne.Start();
            threadTwo.Start();

            Sleep(TimeSpan.FromSeconds(2));
            sample.Stop();
        }

        class ThreadSample
        {
            private bool _isStopped = false;

            public void Stop()
            {
                _isStopped = true;
            }

            public void CountNumbers()
            {
                long counter = 0;

                while (!_isStopped)
                {
                    counter++;
                }

                WriteLine($"{CurrentThread.Name} with " +
                    $"{CurrentThread.Priority,11} priority " +
                    $"has a count = {counter,13:N0}");
            }
        }
    }
线程优先级

7. 前台线程和后台线程(进程会等待所有的前台线程完成后再结束工作,但是如果只剩下后台线程,则会直接结 束工作)

static void Main(string[] args)
        {
            var sampleForeground = new ThreadSample(10);
            var sampleBackground = new ThreadSample(20);

            var threadOne = new Thread(sampleForeground.CountNumbers);
            threadOne.Name = "ForegroundThread";
            var threadTwo = new Thread(sampleBackground.CountNumbers);
            threadTwo.Name = "BackgroundThread";
            threadTwo.IsBackground = true;

            threadOne.Start();
            threadTwo.Start();
        }

        class ThreadSample
        {
            private readonly int _iterations;

            public ThreadSample(int iterations)
            {
                _iterations = iterations;
            }
            public void CountNumbers()
            {
                for (int i = 0; i < _iterations; i++)
                {
                    Sleep(TimeSpan.FromSeconds(0.5));
                    WriteLine($"{CurrentThread.Name} prints {i}");
                }
            }
        }
前台线程和后台线程

8. 向线程传递参数

using static System.Threading.Thread;

namespace Recipe1
{
    class Program
    {
        static void Main(string[] args)
        {
            //通过ThreadSample对象的构造函数传入,再启动线程
            var sample = new ThreadSample(10);
            var threadOne = new Thread(sample.CountNumbers);
            threadOne.Name = "ThreadOne";
            threadOne.Start();
            threadOne.Join();
            WriteLine("--------------------------");
            //使用Thread.Start方法接收一个对象给线程。必须接受object类型的单个参数
            var threadTwo = new Thread(Count);
            threadTwo.Name = "ThreadTwo";
            threadTwo.Start(8);
            threadTwo.Join();

            WriteLine("--------------------------");
            //lambda表达式定义了一个不属于任何类的方法。 该方法使用需要的参数调用了另一个方法,并在另一个线程中运行该方法
            var threadThree = new Thread(() => CountNumbers(12));
            threadThree.Name = "ThreadThree";
            threadThree.Start();
            threadThree.Join();

            WriteLine("--------------------------");
            int i = 10;
            var threadFour = new Thread(() => PrintNumber(i));
            i = 20;
            var threadFive = new Thread(() => PrintNumber(i));
            threadFour.Start();
            threadFive.Start();
            Read();
        }
        static void Count(object iterations)
        {
            CountNumbers((int)iterations);
        }
        static void CountNumbers(int iterations)
        {
            for (int i = 1; i <= iterations; i++)
            {
                Sleep(TimeSpan.FromSeconds(0.5));
                WriteLine($"{CurrentThread.Name} prints {i}");
            }
        }
        static void PrintNumber(int number)
        {
            WriteLine(number);
        }

        class ThreadSample
        {
            private readonly int _iterations;

            public ThreadSample(int iterations)
            {
                _iterations = iterations;
            }
            public void CountNumbers()
            {
                for (int i = 1; i <= _iterations; i++)
                {
                    Sleep(TimeSpan.FromSeconds(0.5));
                    WriteLine($"{CurrentThread.Name} prints {i}");
                }
            }
        }
    }
}
线程各种带参数的方式

9. 线程中的锁(产生死锁)

三个线程共享同一个counter实例,在一个周期 中进行一次递增和一次递减。这将导致不确定的结果(这是因为Counter类并不是线程安全的。当多个线程同时访问counter对象时,第一个 线程得到的counter值10并增加为1"然后第二个线程得到的值是11并增加为12。第一个 线程得到counter值12,但是递减操作发生前,第二个线程得到的counter值也是12。然后 第一个线程将12递减为11并保存回counter中,同时第二个线程进行了同样的操作。结果 我们进行了两次递增操作但是只有一次递减操作,这显然不对)

为了确保不会发生以上情形,必须保证当有线程操作counter对象时,所有其他线程必 须等待直到当前线程完成操作。我们可以使用lock关键字来实现这种行为。如果锁定了一个 对象,需要访问该对象的所有其他线程则会处于阻塞状态,并等待直到该对象解除锁定。这 可能会导致严重的性能问题

 

using System;
using System.Threading;
using static System.Console;

namespace Chapter1.Recipe9
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Incorrect counter");

            var c = new Counter();

            var t1 = new Thread(() => TestCounter(c));
            var t2 = new Thread(() => TestCounter(c));
            var t3 = new Thread(() => TestCounter(c));
            t1.Start();
            t2.Start();
            t3.Start();
            t1.Join();
            t2.Join();
            t3.Join();

            WriteLine($"Total count: {c.Count}");
            WriteLine("--------------------------");

            WriteLine("Correct counter");

            var c1 = new CounterWithLock();

            t1 = new Thread(() => TestCounter(c1));
            t2 = new Thread(() => TestCounter(c1));
            t3 = new Thread(() => TestCounter(c1));
            t1.Start();
            t2.Start();
            t3.Start();
            t1.Join();
            t2.Join();
            t3.Join();
            WriteLine($"Total count: {c1.Count}");
            Read();
        }

        static void TestCounter(CounterBase c)
        {
            for (int i = 0; i < 100000; i++)
            {
                c.Increment();
                c.Decrement();
            }
        }

        class Counter : CounterBase
        {
            public int Count { get; private set; }

            public override void Increment()
            {
                Count++;
            }

            public override void Decrement()
            {
                Count--;
            }
        }

        class CounterWithLock : CounterBase
        {
            private readonly object _syncRoot = new Object();

            public int Count { get; private set; }

            public override void Increment()
            {
                lock (_syncRoot)
                {
                    Count++;
                }
            }

            public override void Decrement()
            {
                lock (_syncRoot)
                {
                    Count--;
                }
            }
        }

        abstract class CounterBase
        {
            public abstract void Increment();

            public abstract void Decrement();
        }
    }
}
线程加锁

10. Monitor类锁定资源(避免死锁)

产生死锁的过程:在该方法中我们先锁定了第一个对象,等待一秒后锁定了 第二个对象。然后在另一个线程中启动该方法。最后尝试在主线程中先后锁定第二个和第一 个对象。

如果像该示例的第二部分一样使用lock关键字,将会造成死锁。第一个线程保持对 lockl对象的锁定,等待直到lock2对象被释放。主线程保持对lock2对象的锁定并等待直到 lockl对象被释放,但lockl对象永远不会被释放。

我们可以直接使用Monitor类。其拥有TryEnter方法,该方法接受一个超时参 数。如果在我们能够获取被lock保护的资源之前,超时参数过期,则该方法会返回false

using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter1.Recipe10
{
    class Program
    {
        static void Main(string[] args)
        {
            object lock1 = new object();
            object lock2 = new object();

            new Thread(() => LockTooMuch(lock1, lock2)).Start();

            lock (lock2)
            {
                Thread.Sleep(1000);
                WriteLine("Monitor.TryEnter allows not to get stuck, returning false after a specified timeout is elapsed");
                if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5)))
                {
                    WriteLine("Acquired a protected resource succesfully");
                }
                else
                {
                    WriteLine("Timeout acquiring a resource!");
                }
            }

            new Thread(() => LockTooMuch(lock1, lock2)).Start();

            WriteLine("----------------------------------");
            lock (lock2)
            {
                WriteLine("This will be a deadlock!");
                Sleep(1000);
                lock (lock1)
                {
                    WriteLine("Acquired a protected resource succesfully");
                }
            }
        }

        static void LockTooMuch(object lock1, object lock2)
        {
            lock (lock1)
            {
                Sleep(1000);
                lock (lock2);
            }
        }
    }
}
避免死锁

11.线程中处理异常

当主程序启动时,定义了两个将会抛出异常的线程。其中一个对异常进行了处理,另 一个则没有。可以看到第二个异常没有被包裹启动线程的try/catch代码块捕获到。所以 如果直接使用线程,一般来说不要在线程中抛出异常,而是在线程代码中使用try/catch 代码块

using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter1.Recipe11
{
    class Program
    {
        static void Main(string[] args)
        {
            var t = new Thread(FaultyThread);
            t.Start();
            t.Join();

            try
            {
                t = new Thread(BadFaultyThread);
                t.Start();
            }
            catch (Exception ex)
            {
                WriteLine("We won't get here!");
            }
        }

        static void BadFaultyThread()
        {
            WriteLine("Starting a faulty thread...");
            Sleep(TimeSpan.FromSeconds(2));
            throw new Exception("Boom!");
        }

        static void FaultyThread()
        {
            try
            {
                WriteLine("Starting a faulty thread...");
                Sleep(TimeSpan.FromSeconds(1));
                throw new Exception("Boom!");
            }
            catch (Exception ex)
            {
                WriteLine($"Exception handled: {ex.Message}");
            }
        }
    }
}
线程中异常(try catch)

 

标签:Thread,C#,void,---,static,线程,WriteLine,new
From: https://www.cnblogs.com/apple-hu/p/18458956

相关文章

  • 20222307 2024-2025-1 《网络与系统攻防技术》实验一实验报告
    1.实验内容1.1本周学习内容进程内存管理在Linux系统中,当OS可执行程序被加载到内存后,其内存布局主要包括三个关键段:*.text段:包含程序的指令,这些指令是只读的,用于指导CPU执行操作。*.data段:存储静态初始化数据,这些数据是可写的,程序在运行时可以直接访问和修改。*.bss段:用......
  • WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现C
    1、新建了一个用户控件,里面画了一个实心圆,以及一个文本控件的组合,当作我要实验使用的用户控件(TestUserControl)。 2、在主窗体里面进行引用,可以看到引用以后,会在工具箱上显示新增的用户控件3、为了测试方便,我直接在先前的Lo'gin页面直接进行添加该用户控件,效果如下。 4、......
  • MongoDB安装及配置Navicat MongoDB Tools
    一、下载MongoDB1.下载网址:https://www.mongodb.com/try/download/community注:本文档以Windows和msi安装为例二、安装MongoDB打开.msi文件在硬盘任意位置创建mongo目录,内包含mongo.conf文件内容:#存放数据目录dbpath=D:\mongo\data\db端口port=27017日志......
  • ROS1,用C++实现获取激光雷达数据,并使用gazebo测试
    实现步骤构建一个新的软件包,包名叫做lidar_pkg。cdcatkin_ws/src/catkin_create_pkglidar_pkgroscpprospysensor_msgs输入code,打开vscode在软件包中新建一个节点,节点名叫做lidar_node。在节点中,向ROS大管家NodeHandle申请订阅话题/scan,并设置回调函数为......
  • EPICS的学习1
    EPICS的学习1本人因为工作需要学习EPICS的使用,于是去网上研究这个,发现资料不多,而且比较杂乱,而且基本上只能去看英文文档,故花费了自己不少的时间。决定将自己的学习整理成笔记,发在网上,以后有需要的可以也来学习和看看,如果对我的笔记中感到疑惑产生了问题,也可以在评论区提出。安装......
  • 你的Mac电脑的terminal还是黑白的吗?快来设置一下吧
    更改ls显示目录的颜色进入terminal,进入~目录:cd~编辑.bash_profile文件:vim.bas_profile按i进入编辑态,添加以下三行代码 exportLS_OPTIONS='--color=auto' #如果没有指定,则自动选择颜色   exportCLICOLOR='Yes' #是否输出颜色exportLSCOLORS='gxfxaxd......
  • (29-6-02)通过回测、ARIMA 和 GRU 预测股票价格:深度学习模型预测(2)
    29.8.4 训练和测试数据集的划分训练和测试数据集的划分是机器学习中评估模型在未见数据上的表现的重要过程。通过将数据集分成两个部分:训练集用于训练模型,测试集用于评估模型的性能,我们可以更好地了解模型对新数据的泛化能力。这一过程可以帮助我们避免过拟合,即模型在训练......
  • Windows多线程编程 互斥量和临界区使用
    Windows多线程编程允许程序同时运行多个线程,提高程序的并发性和执行效率。多线程编程中的核心概念包括线程的创建、同步、调度、数据共享和竞争条件等。本文详细介绍了Windows多线程编程的关键技术点,并解释如何使用线程同步机制来保证线程安全。1.线程基础概念1.1线......
  • Redis-02 数据持久化
    redis持久化即将数据从内存写入磁盘,Redis提供了两种持久化的方式:RDB和AOF。1.RDBRDB持久化:Redis可以将内存中的数据定期快照保存到磁盘上的一个二进制文件中。RDB持久化是一种比较紧凑的文件格式,适用于备份和灾难恢复。通过配置Redis的持久化策略,可以设置Redis定期保存快......
  • 有关 OneDrive 中 Copilot 的常见问题解答
    很多小伙伴已经用上了OneDrive中的Copilot功能:Copilot重磅更新!OneDrive全新功能炸裂一个技巧实现在SharePoint中使用Copilot针对大家提问比较多的问题,在此做一个汇总:1、OneDrive中的Copilot目前在哪里可用?OneDrive中的Copilot目前在 OneDriveWeb上仅适用于商......