C#专题之线程

5.1 资源访问冲突问题


internal class StateObject
{
    private int state = 5;
    public void ChangeState()
    {
        if (state == 5)
        {
            state++;
            Console.WriteLine("state: " + state + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
        }
        state = 5;
    }
}
static void Main(string[] args)
{
    StateObject state = new StateObject();

    for (int i = 0; i < 100; i++)
    {
        Thread t = new Thread(state.ChangeState);
        t.Start();
    }
}

解决——加锁

internal class StateObject
{
    private Object _lock = new Object();

    private int state = 5;
    public void ChangeState()
    {
        lock (_lock)
        {
            if (state == 5)
            {
                state++;
                Console.WriteLine("state: " + state + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
            }
            state = 5;
        }
    }
}

异步委托的方式启动线程


static void Test()
{
    Console.WriteLine("Test Started");
    Console.WriteLine("Test Running");
    Thread.Sleep(3000);
    Console.WriteLine("Test Completed");
}

delegate void TestDelegate();

static void Main(string[] args)
{
    TestDelegate testDelegate = Test;
    testDelegate.BeginInvoke(null, null);
    Console.WtiteLine("Main Completed");
}

线程的优先级和线程的状态


线程的优先级

在 Thread 类中,可以设置 Priority​ 属性,以影响线程的基本优先级,Priority​ 属性是 ThreadPriority​ 枚举定义的一个值。定义的级别有:Highest​、AboveNormal​、Normal​、BelowNormal​ 和 Lowest​。

线程的状态

  • 获取线程的状态(Running 还是 Unstarted…),当我们通过调用 Thread 对象的 Start() 方法,可以创建线程,但是调用了 Start()​ 方法之后,新线程不是马上进入 Running 状态,而是处于 Unstarted 状态,只有当操作系统的线程调度器选择了要运行的线程,这个线程的状态才会修改为 Running 状态。我们使用 Thread.Sleep()​ 方法可以让当前线程休眠进入 WaitSleepJoin 状态。
  • 使用 Thread对象的 Abort()​ 方法可以停止线程。调用这个方法,会在要终止的线程中抛出一个 ThreadAbortException​ 类型的异常,我们可以 try catch 这个异常,然后在线程终止前做一些清理的工作。
  • 如果需要等待线程的结束,可以调用 Thread 对象的 Join()​ 方法,表示把 Thread 加入进来,暂停当前线程,并把它设置为 WaitSleepJoin 状态,直到加入的线程完成为止。

线程池


static void Main(string[] args)
{
    for (int i = 0; i < 10; i++)
    {
        ThreadPool.QueueUserWorkItem(Download);
    }
    Thrad.Sleep(500);
}

static void Download(Object state)
{
    for (int i = 0; i < 3; i++)
    {
        Console.WriteLine("Downloading...: " + Thread.CurrentThread.ManageThreadId);
        Thread.Sleep(100);
    }
}
  • 使用线程池启动的线程默认是后台线程
  • 如果进程的所有前台线程都结束了,所有的后台线程就会停止,不能把入池的线程改为前台线程。
  • 不能给入池的线程设置优先级或名称
  • 入池的线程只能用于时间较短的任务,如果线程要一直运行,就应该使用 Thread​ 类创建一个线程。

死锁问题


internal class StateObject
{
    private Object _lock1 = new Object();
    private Object _lock2 = new Object();
  
    private int state1 = 5;
    private int state2 = 5;
  
    public void ChangeState()
    {
        Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第1把锁");
        lock (_lock1)
        {
             lock (_lock2)
            {
                Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第2把锁");
                if (state1 == 5)
                {
                    state1++;
                    Console.WriteLine("state: " + state1 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                }
                state1 = 5;
  
                if (state2 == 5)
                {
                    state2++;
                    Console.WriteLine("state: " + state2 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                }
                state2 = 5;
            }
        }
    }

    public void ChangeState()
    {
        lock (_lock2)
        {
            Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第2把锁");
             lock (_lock1)
            {
                Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第1把锁");
                if (state1 == 5)
                {
                    state1++;
                    Console.WriteLine("state: " + state1 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                }
                state1 = 5;
  
                if (state2 == 5)
                {
                    state2++;
                    Console.WriteLine("state: " + state2 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                }
                state2 = 5;
            }
        }
    }
}

解决方法——规定相同的拿锁顺序

internal class StateObject
{
    private Object _lock1 = new Object();
    private Object _lock2 = new Object();
  
    private int state1 = 5;
    private int state2 = 5;
  
    public void ChangeState()
    {
        Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第1把锁");
        lock (_lock1)
        {
             lock (_lock2)
            {
                Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第2把锁");
                if (state1 == 5)
                {
                    state1++;
                    Console.WriteLine("state: " + state1 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                }
                state1 = 5;
  
                if (state2 == 5)
                {
                    state2++;
                    Console.WriteLine("state: " + state2 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                }
                state2 = 5;
            }
        }
    }

    public void ChangeState()
    {
        lock (_lock1)
        {
            Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第1把锁");
             lock (_lock2)
            {
                Console.WriteLine(Thread.CurrentThread.ManageThreadId + "拿到了第2把锁");
                if (state1 == 5)
                {
                    state1++;
                    Console.WriteLine("state: " + state1 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                }
                state1 = 5;
  
                if (state2 == 5)
                {
                    state2++;
                    Console.WriteLine("state: " + state2 + " 线程ID:" + Thread.CurrentThread.ManageThreadId);
                }
                state2 = 5;
            }
        }
    }
}

使用Thread启动线程和传输数据


启动线程

static void Test()
{
    Console.WriteLine("Test Started");
    Console.WriteLine("Test Running");
    Thread.Sleep(1000);
    Console.WriteLine("Test Completed");
}

static void Main(string[] args)
{
    Thread t = new Thread(Test);
    t.Start();
    Console.WriteLine("Main Completed");
}

使用 Lambda 表达式:

static void Main(string[] args)
{
    Thread t = new Thread(() => Console.WriteLine("Child Thread: " + Thread.CurrentThread.ManageThreadId));
    t.Start();
    Console.WriteLine("Main Completed: " + Thread.CurrentThread.ManageThreadId);
}

使用匿名方法:

static void Main(string[] args)
{
    Thread t = new Thread(delegate () {
        Console.WriteLine("Child Thread: " + Thread.CurrentThread.ManageThreadId)
    });
    t.Start();
    Console.WriteLine("Main Completed: " + Thread.CurrentThread.ManageThreadId);
}

传递数据

static void Download(Object x)
{
    string str = o as string;
    Console.WriteLine(str);
}

static void Main(string[] args)
{
    Thread t = new Thread(Download);
    t.Start("http://www.xxx.com");
}

Start()​ 方法只能接收无参的方法或只有一个参数的方法

传递多个数据

public struct Data
{
    public string message;
    public int age;
}

static void Download(Object x)
{
    Data data = (Data)o;
    Console.WriteLine(data.message);
    Console.WriteLine(data.age);
}

static void Main(string[] args)
{
    Data data = new Data();
    data.message = "";
    data.age = 12;  

    Thread t = new Thread(Download);
    t.Start(data);
}

任务


static void Main(string[] args)
{
    TaskFactory tf = new TaskFactory();
    Task t = tf.StartNew(Test);
    Thread.Sleep(5000);
}

static void Test()
{
    for (int i = 0; i < 10000; i++)
    {
        Console.WriteLine("A");
    }
}
static void Main(string[] args)
{
    Task t = new Task(Test);
    t.Start();
    Thread.Sleep(5000);
}

static void Test()
{
    for (int i = 0; i < 10000; i++)
    {
        Console.WriteLine("A");
    }
}

连续任务

如果一个任务t1的执行是依赖于另一个任务t2的,那么就需要在这个任务t2执行完毕后才开始执行t1。这个时候我们就可以使用连续任务。

static void FirstDownload()
{
    Console.WriteLine("Downloading ...");
    Thread.Sleep(2000);
}

static void SecondAlert(Task t)
{
    Console.WriteLine("下载完成!");
}

static void Main(string[] args)
{
    Task t1 = new Task(FirstDownload);
    t1.ContinueWith(SecondAlert);
    t1.Start();
    Thread.Sleep(5000);
}
static void FirstDownload()
{
    Console.WriteLine("Downloading ...");
    Thread.Sleep(2000);
}

static void SecondAlert(Task t)
{
    Console.WriteLine("下载完成!");
}

static void Main(string[] args)
{
    Task t1 = new Task(FirstDownload);
    Task t2 = t1.ContinueWith(SecondAlert);
    Task t3 = t2.ContinueWith(SecondAlert);
    t1.Start();
    Thread.Sleep(5000);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/744780.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java银系统/超市收银系统/智慧新零售/ERP进销存管理/线上商城/h5/小程序

>>>系统简述&#xff1a; 神点收银系统支持B2B2C多商户模式&#xff0c;系统基于前后端分离的架构&#xff0c;后端采用Java SpringBoot Mysql Mybatis Plus&#xff0c;前端基于当前流行的Uniapp、Element UI&#xff0c;支持小程序、h5。架构包含&#xff1a;会员端…

Redis-数据类型-Bit的基本操作-getbit-setbit-Bitmap

文章目录 0、Bitmaps&#xff08;位图&#xff09;1、查看redis是否启动2、通过客户端连接redis3、切换到db7数据库4、设置&#xff08;或覆盖&#xff09;一个键&#xff08;key&#xff09;的值&#xff08;value&#xff09;5、获取存储在给定键&#xff08;key&#xff09;…

还是国产大模型靠谱!这里有一个OpenAI API用户特别搬家计划

近日&#xff0c;一场风波在科技圈引起了广泛的关注。6月25日凌晨&#xff0c;OpenAI向大量开发者发送邮件&#xff0c;通知他们&#xff1a;“您的组织有流量来自来OpenAl目前不支持的地区。从7月9日起&#xff0c;我们将采取额外措施&#xff0c;停止OpenAI不支持的国家和地区…

智慧车库管理系统

摘 要 随着城市化进程的不断加快&#xff0c;私家车数量的快速增长给城市交通带来了巨大的挑战&#xff0c;停车问题成为城市交通管理中的一大难题。车辆停车时&#xff0c;在停车场寻找停车位耗时过久&#xff0c;不仅仅浪费用户的时间&#xff0c;还可能引起交通拥堵。城市停…

python笔记3

1.通过乘法多次打印&#xff0c;以及字符串相加的合体打印 xzzz yyyy print(xy) print(x*10)#与一个数为打印多少次 2.设置俩个变量&#xff0c;可以通过下面的方法来判断是否一个元素是否在另一个元素中&#xff0c;返回bool值 xzzz yyyy print(xy) print(x*10)#与一个数为打…

论文辅导 | 基于贝叶斯优化LSTM的锂电池健康状态评估方法

辅导文章 模型描述 在传统的 LSTM 神经网络中,超参数的取值对模型性能有很大影响,但人工调参很难得到最优解。 因此,本文加入了 BO 来迭代出最优超参数。 在利用LSTM 神经网络评估锂电池 SoH 的基础上,通过 BO来提高评估的精确度。 预测效果

【以Qwen2为例】vLLM流式推理部署,openai接口调用,requests调用

大家都是穷鬼&#xff0c;都不喜欢看到 现在csdn上关于vllm流式推理部署的文章全部都收费&#xff0c;这么简单的一个技术至于这样吗&#xff1f;都藏着掖着 安装vllm 我的torch版本是2.3.0&#xff0c;对应nccl是2.20.5 pip install nvidia-nccl-cu122.20.5部署 python -m…

Java | Leetcode Java题解之第198题打家劫舍

题目&#xff1a; 题解&#xff1a; class Solution {public int rob(int[] nums) {if (nums null || nums.length 0) {return 0;}int length nums.length;if (length 1) {return nums[0];}int first nums[0], second Math.max(nums[0], nums[1]);for (int i 2; i <…

SpringBoot整合Mybatis并实现数据库增删改查

写在前面 Mybatis一个基于Java的持久层框架&#xff0c;它通过XML或注解的方式&#xff0c;将SQL语句和Java方法进行映射&#xff0c;使得开发者可以轻松地进行数据库操作。下面我会演示mybatis的配置与使用并实现数据库的增删改查。 1.准备测试数据 使用mybatis实现对数据库…

石油化工厂为什么要用专业防爆手机?

防爆手机之所以必须使用专业设计的产品&#xff0c;主要是出于安全考虑&#xff0c;以防止在易燃易爆环境中因手机使用不当引发爆炸事故。以下几点详细解释了使用专业化工防爆手机的必要性&#xff1a; 本质安全设计&#xff1a;顶坚专业防爆手机采用了本质安全&#xff08;本安…

权重衰退及代码

一、硬性限制 1、通常不限制偏移b&#xff0c;因为限制不会有区别&#xff1b;seta越小&#xff0c;意味着正则项强 2、优化的是最小化的损失函数 3、后部的限制条件&#xff0c;每个项的平方和小于一个值&#xff1b;极端情况下&#xff0c;当seta等于0&#xff0c;意味着所…

【node】深入探讨 class URL

【node】深入探讨 class URL &#x1f4cc; 浅说 fileURLToPath() 在vite.config.ts中有这么一段代码&#xff1a; import { fileURLToPath, URL } from node:url import { defineConfig } from vite export default defineConfig({resolve: {alias: {: fileURLToPath(new U…

github无法访问,下载慢的解决方法

GitHub是一个存储分享无数的开源项目和代码的宝库网站。然而&#xff0c;由于一些原因&#xff0c;国内用户在访问GitHub时常常遭遇无法访问或下载速度缓慢的问题。这不仅影响了开发者的工作效率&#xff0c;也使一些想要访问下载github文件的普通用户遇到困难。下面小编就来和…

线性代数、矩阵计算

一、线性代数 1、对于向量&#xff0c;若a是标量&#xff0c;为a的绝对值乘以b的向量长度。 2、点乘 3、范数&#xff1a;向量或者矩阵的长度 L1范数&#xff1a;&#xff08;对向量&#xff09;每个元素的绝对值求和 L2范数&#xff1a;&#xff08;对向量&#xff09;torch.…

Websocket在Java中的实践——最小可行案例

WebSocket是一种先进的网络通信协议&#xff0c;它允许在单个TCP连接上进行全双工通信&#xff0c;即数据可以在同一时间双向流动。WebSocket由IETF标准化为RFC 6455&#xff0c;并且已被W3C定义为JavaScript API的标准&#xff0c;成为现代浏览器的重要特性之一。 WebSocket的…

【嵌入式Linux】i.MX6ULL 外部中断服务函数的初始化

文章目录 1. Cortex-A7 中断系统1.1 分析1.2 具体处理流程 2. 外部中断服务函数的初始化2.1 基本流程分析2.2 具体代码分析2.2.1. 定义中断处理类型和结构体2.2.2. 初始化中断系统2.2.3. 注册中断处理函数2.2.4. 具体的中断处理逻辑2.2.5. 默认的中断处理函数 3. 完整代码 本文…

002_unsigned long数据比较的坑?

【背景】 unsigned long 类似数据的比较问题&#xff0c;先上一段代码&#xff0c;如下图所示&#xff1a; 就是图中框出的部分&#xff0c;眨眼一看&#xff0c;应该没啥问题&#xff0c;而且我也在本地的编译器vs2019上编译了&#xff0c;确实也没有报错&#xff0c;所以就修…

【Linux】静态库、动态库

动静态库里面包含的是源文件通过汇编阶段生成的后缀为.o的可重定位目标文件。我们在使用C语言&#xff0c;包含一个stdio.h头文件就可以使用scanf方法&#xff0c;其实都是系统调用了相应的头文件和库&#xff0c;库里面有开发者已经写好各种方法。也就是说我们在使用C语言时&a…

Java | Leetcode Java题解之第191题位1的个数

题目&#xff1a; 题解&#xff1a; public class Solution {public int hammingWeight(int n) {int ret 0;while (n ! 0) {n & n - 1;ret;}return ret;} }

【学习】软件测试中常见的文档类型及其作用

在软件开发的生命周期中&#xff0c;软件测试是确保产品质量的关键步骤。为了系统地进行测试活动&#xff0c;并保证测试结果的有效性和可追溯性&#xff0c;产生了一系列标准化的测试文档。这些文档不仅为测试人员提供了执行指南&#xff0c;而且为项目管理者和利益相关者提供…