面試常考:C#用兩個線程交替列印1-100的五種方法

来源:https://www.cnblogs.com/xbhp/archive/2023/03/21/17239585.html
-Advertisement-
Play Games

"C#用兩個線程交替列印1-100的五種方法"是.NET工程師面試多線程常考的試題之一,主要考察對C#語法和對多線程的熟悉程度。本文將用5種方法實現這個面試題。 方法1:使用Mutex或lock 這種方法涉及使用Mutex或lock對象來同步兩個線程。其中一個線程負責列印偶數,另一個線程負責列印奇數 ...


    "C#用兩個線程交替列印1-100的五種方法"是.NET工程師面試多線程常考的試題之一,主要考察對C#語法和對多線程的熟悉程度。本文將用5種方法實現這個面試題。

方法1:使用Mutex或lock

    這種方法涉及使用Mutex或lock對象來同步兩個線程。其中一個線程負責列印偶數,另一個線程負責列印奇數。線程在執行任務之前會鎖定共用的Mutex或lock對象,以確保每個線程執行任務時只有一個線程能夠訪問共用資源。代碼如下:

class Program
{
    static Mutex mutex = new Mutex();
    static int count = 1;
    static void Main(string[] args)
    {
        Thread t1 = new Thread(PrintOddNumbers);
        Thread t2 = new Thread(PrintEvenNumbers);
        t1.Start();
        t2.Start();
        t1.Join();
        t2.Join();
        Console.ReadLine();
    }
    static void PrintOddNumbers()
    {
        while (count <= 100)
        {
            mutex.WaitOne();
            if (count % 2 == 1)
            {
                Console.WriteLine("Thread 1: " + count);
                count++;
            }
            mutex.ReleaseMutex();
        }
    }
    static void PrintEvenNumbers()
    {
        while (count <= 100)
        {
            mutex.WaitOne();
            if (count % 2 == 0)
            {
                Console.WriteLine("Thread 2: " + count);
                count++;
            }
            mutex.ReleaseMutex();
        }
    }
}

方法2:使用AutoResetEvent

AutoResetEvent是一種線程同步機制,允許一個線程等待另一個線程發出信號來繼續執行。其中一個線程負責列印奇數,另一個線程負責列印偶數。當一個線程完成列印任務時,它發出信號以喚醒另一個線程來繼續執行。

class Program
{
    static AutoResetEvent oddEvent = new AutoResetEvent(false);
    static AutoResetEvent evenEvent = new AutoResetEvent(false);
    static int count = 1;
    static void Main(string[] args)
    {
        Thread t1 = new Thread(PrintOddNumbers);
        Thread t2 = new Thread(PrintEvenNumbers);
        t1.Start();
        t2.Start();
        t1.Join();
        t2.Join();
        Console.ReadLine();
    }

    static void PrintOddNumbers()
    {
        while (count <= 100)
        {
            if (count % 2 == 1)
            {
                Console.WriteLine("Thread 1: " + count);
                count++;
                evenEvent.Set();
                oddEvent.WaitOne();
            }
        }
    }

    static void PrintEvenNumbers()
    {
        while (count <= 100)
        {
            if (count % 2 == 0)
            {
                Console.WriteLine("Thread 2: " + count);
                count++;
                oddEvent.Set();
                evenEvent.WaitOne();
            }
        }
    }
//歡迎關註公眾號“DOTNET開發跳槽”,關註可獲得海量面試題

方法3:使用Monitor

Monitor是C#中的一種同步機制,類似於Mutex。其中一個線程負責列印奇數,另一個線程負責列印偶數。線程在執行任務之前會鎖定共用的Monitor對象,以確保每個線程執行任務時只有一個線程能夠訪問共用資源。

class Program
{
    static object lockObj = new object();
    static int count = 1;
    static void Main(string[] args)
    {
        Thread t1 = new Thread(PrintOddNumbers);
        Thread t2 = new Thread(PrintEvenNumbers);
        t1.Start();
        t2.Start();
        t1.Join();
        t2.Join();
        Console.ReadLine();
    }

    static void PrintOddNumbers()
    {
        while (count <= 100)
        {
            lock (lockObj)
            {
                if (count % 2 == 1)
                {
                    Console.WriteLine("Thread 1: " + count);
                    count++;
                }
            }
        }
    }

    static void PrintEvenNumbers()
    {
        while (count <= 100)
        {
            lock (lockObj)
            {
                if (count % 2 == 0)
                {
                    Console.WriteLine("Thread 2: " + count);
                    count++;
                }
            }
        }
    }
}

方法4:使用信號量Semaphore

Semaphore是一種同步機制,允許多個線程同時訪問共用資源。其中一個線程負責列印奇數,另一個線程負責列印偶數。線程在執行任務之前會等待信號量,以確保每個線程只有在獲得信號量之後才能訪問共用資源。

class Program
{
    static Semaphore semaphore = new Semaphore(1, 1);
    static int count = 1;
    static void Main(string[] args)
    {
        Thread t1 = new Thread(PrintOddNumbers);
        Thread t2 = new Thread(PrintEvenNumbers);
        t1.Start();
        t2.Start();
        t1.Join();
        t2.Join();

        Console.ReadLine();
    }

    static void PrintOddNumbers()
    { //註意 這裡是99,否則會出現101
        while (count <= 99)
        {
            semaphore.WaitOne();
            if (count % 2 == 1)
            {
                Console.WriteLine("Thread 1: " + count);
                count++;
            }
            semaphore.Release();
        }
    }

    static void PrintEvenNumbers()
    {
        while (count <= 100)
        {
            semaphore.WaitOne();
            if (count % 2 == 0)
            {
                Console.WriteLine("Thread 2: " + count);
                count++;
            }
            semaphore.Release();
        }
    }
}

方法5:使用Task和async/await

在C#中,使用Task和async/await關鍵字可以輕鬆地在兩個線程之間切換執行。其中一個線程負責列印奇數,另一個線程負責列印偶數。線程在執行任務之前使用async/await等待非同步任務完成,以確保每個線程只在非同步任務完成後才訪問共用資源。

class Program
{
    static int count = 1;
    static void Main(string[] args)
    {
        Task.Run(PrintOddNumbers);
      // 這裡改成這個也可以
      // var thread1 = new Thread(PrintOddNumbers);
        Task.Run(PrintEvenNumbers);
        Console.ReadLine();
    }
  //如果用Thread改成同步方法
    static async Task PrintOddNumbers()
    {
        while (count <= 100)
        {
            if (count % 2 == 1)
            {
                Console.WriteLine("Thread 1: " + count);
                count++;
                //如果用Thread這裡改成 Thread.Sleep(1);
                await Task.Delay(1);
            }
        }
    }
    static async Task PrintEvenNumbers()
    {
        while (count <= 100)
        {
            if (count % 2 == 0)
            {
                Console.WriteLine("Thread 2: " + count);
                count++;
                await Task.Delay(1);
            }
        }
    }
//歡迎關註公眾號“DOTNET開發跳槽”,關註可獲得海量面試題

五種效果如下:

 

 

以上五種方法各有優缺點,沒有一種方法是絕對最優的,取決於應用場景和要求。以下是對五種方法的簡單比較和說明:1、使用ManualResetEventWaitHandle:這種方法在實現上較為簡單,但是由於線程必須互斥地訪問共用資源,因此會導致性能瓶頸。此外,使用ManualResetEventWaitHandle需要頻繁調用WaitOne和Set方法,可能會降低應用程式的響應能力。2、使用AutoResetEventWaitHandle:這種方法在實現上比較簡單,而且使用AutoResetEventWaitHandle可以避免性能瓶頸問題。然而,它仍然需要頻繁調用WaitOne和Set方法,可能會降低應用程式的響應能力。3、使用鎖:使用鎖可以避免性能瓶頸問題,因為同一時間只有一個線程可以訪問共用資源。但是,鎖可能會導致線程死鎖和性能下降的問題,因此需要小心使用。4、使用信號量Semaphore:這種方法可以避免性能瓶頸問題,並允許多個線程同時訪問共用資源。Semaphore還可以設置多個許可證,以控制併發線程的數量。然而,使用Semaphore可能會使代碼變得更加複雜,因此需要小心使用。5、使用Task和async/await:這種方法可以避免性能瓶頸問題,並且使用Task和async/await可以使代碼更加簡潔易懂。但是,它可能會對記憶體和CPU產生額外的開銷,因為需要在任務之間頻繁地切換上下文。綜上所述,選擇哪種方法取決於應用程式的要求和程式員的個人偏好。如果應用程式需要更好的性能,則應該使用鎖或信號量;如果應用程式需要更簡潔易懂的代碼,則應該使用Task和async/await。

考察的知識點

1、C#編程語言和語法:實現多線程程式需要熟悉C#編程語言和語法,包括線程的創建和管理、共用資源的訪問和同步等方面的知識。2、多線程編程:多線程編程是指同時運行多個線程的編程模型,它可以提高應用程式的性能和響應能力。多線程編程需要考慮線程的同步、共用資源的訪問、線程間的通信等問題。3、線程同步機制:線程同步機制是指用於控制多個線程訪問共用資源的機制,常用的線程同步機制包括鎖、信號量、事件等。4、非同步編程:非同步編程是指不阻塞線程並且在完成任務後通知線程的編程模型,它可以提高應用程式的響應能力和性能。非同步編程需要熟悉非同步和await關鍵字、Task和Task<T>等類型、async和await方法等概念。參考:chatGPT
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安全配置Security Defenses 通過對Security Defenses的配置 ,可以對http頭添加相應的安全配置 ,如csp, X-Frame-Options, X-Content-Type-Option等 1 X-Frame-Options 你的網站添加了X-Frame-Optio ...
  • 說明 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。 1. 使用前的準備 參考本人另一篇博客 安裝 Visual Leak Detector 下載 vld-2.5.1-setup.exe 並按步驟安裝 VLD。這一種使用方式的缺點是,當把項目拷貝到別的電腦上編譯運行時,需要按以下流程重新配 ...
  • 由於 Blazor-WebAssembly 是在瀏覽器中運行的,通常不需要執行伺服器代碼,只要有個“窩”能托管並提供相關文件的下載即可。所以,當你有一個現成的 Blazor wasm 項目,沒必要用其他語言重寫,或者你不想用 ASP.NET Core 來托管(有些大材小用了),就可以試試用 node ...
  • 1. Grid佈局 ,(Table 佈局) 兩行兩列佈局, Border 0 行 0 列預設開始 <Window x:Class="WpfApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ...
  • 1 枚舉 enum E_MonsterType//定義了一個枚舉的變數類型 { normal1,//0 boss = 5,//5 normal2,//6,前一個自動加1 } //枚舉和switch語句天生一對,寫switch時能對枚舉類型自動補全 E_MonsterType monsterType ...
  • 用了很多年的Rapid SCADA v5,現在官網已經推出了v6,就簡單寫一下有關v6的安裝指南吧。 本指南面向Windows用戶,不適用於linux用戶 步驟 從官網下載Rapid SCADA最新的RC版本的v6,然後運行壓縮包內的ScadaSetup.exe程式。 FAQ 提示埠占用 Rapi ...
  • 簡介 本文主要介紹使用 利用 SqlSugar 來實現多資料庫的維護 ,動態建類CRUD,動態建表 ,全局過濾器 ,跨庫查詢等功能 1、創建表 SqlSugar支持了3種模式的建表(無實體建表、實體建表,實體特性建表),非常的靈活 可以多個資料庫 MYSQL MSSQL ORACLE SQLITE ...
  • 十年河東,十年河西,莫欺少年窮 學無止境,精益求精 netcore3.1控制台應用程式,引入MQTTnet 2.8版本 訂閱端: using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Text; ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...