92027


提示コードの`コンバート`関数の`///`コメント部のコードですが`semaphore`を利用している非同期処理で処理が進みません。これはなぜでしょうか？  
おそらく`semaphore.Wait();`の使い方だと思うのですが下記のリファレンス通り

[code]

    `SemaphoreSlim に入れるようになるまで、現在のスレッドをブロックします。`
    
[/code]

なのでこの場合だと三つ以上のスレッドが立った時それ以上立たないようにするためのストッパーなのではないのでしょうか？どうなのでしょうか？原因はわかんらいのですがTask.Run()の中身が実行されまない原因が知りたいです。

参考サイト：https://learn.microsoft.com/ja-
jp/dotnet/api/system.threading.semaphoreslim.wait?view=net-6.0

##### 出力ログ

[code]

    'HEIC_SimpleConverter.exe' (CoreCLR: clrhost): 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.10\System.ObjectModel.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。
    'HEIC_SimpleConverter.exe' (CoreCLR: clrhost): 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.10\System.Private.Uri.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。
    aaaaa 5
    'HEIC_SimpleConverter.exe' (CoreCLR: clrhost): 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.10\System.ComponentModel.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。
    スレッド 0x4710 はコード 0 (0x0) で終了しました。
    スレッド 0x2934 はコード 0 (0x0) で終了しました。
    スレッド 0x622c はコード 0 (0x0) で終了しました。
    
    
[/code]

[code]

    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Runtime.ConstrainedExecution;
    using System.Threading;
    using System.Windows.Forms;
    using ImageMagick;
    
    namespace HEIC_SimpleConverter
    {
        public partial class Form : System.Windows.Forms.Form
        {
            public Form()
            {
                InitializeComponent();
               
            }
    
            string saveFolder;
            SemaphoreSlim semaphore = new SemaphoreSlim(0,3);
            List<string> file = new List<string>();
            float per = 0;
            string folderPath = "";
            List<Task> task = new List<Task>();
    
            /*##########################################################################
            # D&D されたとき
            ############################################################################*/
            private void Form_DragDrop(object sender, DragEventArgs e)
            {
                string[] str = (string[])e.Data.GetData(DataFormats.FileDrop, false);
                //Debug.WriteLine(str[0]);
    
                for (int i = 0; i < str.Length; i++)
                {
                    file.Add(str[i]);
                    listBox.Items.Add(Path.GetFileName(str[i]));
                }
            }
    
    
            /*##########################################################################
            # ファイルがウインドウに乗った時
            ############################################################################*/
            private void Form_DragEnter(object sender, DragEventArgs e)
            {
                if (e.Data.GetDataPresent(DataFormats.FileDrop))
                {
                    string[] str = (string[])e.Data.GetData(DataFormats.FileDrop, false);
    
                    bool flag = false;
                    for(int i = 0; i < str.Length; i++)
                    {
                        string ext = Path.GetExtension(str[i]);
                        if ( (ext != ".HEIC") && (ext != "HEIF") )
                        {
                            flag = true;
                            break;
                        }
                    }
    
                    if(flag == true)
                    {
                        e.Effect = DragDropEffects.None;
                    }
                    else
                    {
                        e.Effect = DragDropEffects.All;
                    }
                }
                else
                {
                    e.Effect = DragDropEffects.None;
                }
    
            }
    
            /*##########################################################################
            # コンバートボタン　クリック
            ############################################################################*/
            private void button_Click(object sender, EventArgs e)
            {
                folderBrowserDialog.ShowDialog();                   //保存場所表示
                folderPath = folderBrowserDialog.SelectedPath;      //保存場所を格納
    
                Convert();      //保存ディレクトリ指定
            }
    
    
            /*##########################################################################
            # コンバート
            ############################################################################*/
            private async void Convert()
            {
                progressBar.Value = 0;
                per = 100.0f / (float)file.Count();
    
    
                Debug.WriteLine("aaaaa " + file.Count);
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                for (int i = 0; i < file.Count; i++)
                {
                    task.Add(Task.Run(() =>
                    {
                        semaphore.Wait();
                        Debug.WriteLine("file.Count " + file.Count);
    
                        Debug.WriteLine(file[4]);
    
                        /*
                        string filePath = folderPath + "/" + Path.GetFileName(file[i].ToString()) + ".jpeg";
                        string f = Path.ChangeExtension(file[i].ToString(), "jpeg");
                        ImageMagick.MagickImage img = new ImageMagick.MagickImage(file[i].ToString());
                        img.Write(filePath);
                        img.Dispose();
    
    
                        this.Invoke( () => { progressBar.Value += (int)per; } );
                        */
    
                        semaphore.Release();
                    }));
                }
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                button.Enabled = false;
                await Task.WhenAll(task.ToArray());
                semaphore.Dispose();
    
                button.Enabled = true;
    
                //リセット
                progressBar.Value = 0;
                file.Clear();
                listBox.Items.Clear();
            }
    
            
    
    
    
    
    
    
            private void Form_Load(object sender, EventArgs e)
            {
    
            }
    
            
    
        }
    }
    
[/code]


CC BY-SA 4.0
2022-11-06T04:55:26.603
92024
2022-11-06T06:11:03.677
2022-11-06T06:11:03.677
4236
55177
question
c# .net winforms .net-core
非同期処理　SemaphoreSlim.Wait()使い方が知りたい。Task.Runが実行されない原因が知りたい


[SemaphoreSlim コンストラクター](https://learn.microsoft.com/ja-
jp/dotnet/api/system.threading.semaphoreslim.-ctor?view=net-6.0#system-
threading-semaphoreslim-ctor\(system-int32-system-int32\))は

>
[code]

>     public SemaphoreSlim (int initialCount, int maxCount);
>  
[/code]

となっています。サンプルおよび質問のコードは

[code]

    SemaphoreSlim semaphore = new SemaphoreSlim(0,3);
    
[/code]

となっているので初期値`0`、最大値`3`です。

一方、[`SemaphoreSlim.Wait`メソッド](https://learn.microsoft.com/ja-
jp/dotnet/api/system.threading.semaphoreslim.wait?view=net-6.0)は

> スレッドまたはタスクがセマフォを入力できる場合は、プロパティを CurrentCount 1 ずつデクリメントします。

とあります。  
初期値が`0`ですので最初から詰んだ状態で`SemaphoreSlim.Wait()`が通過するためにはその前に[`SemaphoreSlim.Release()`](https://learn.microsoft.com/ja-
jp/dotnet/api/system.threading.semaphoreslim.release?view=net-6.0)で許可する必要があります。実際、参照されたコードには

>
[code]

>     // Restore the semaphore count to its maximum value.
>     Console.Write("Main thread calls Release(3) --> ");
>     semaphore.Release(3);
>     Console.WriteLine("{0} tasks can enter the semaphore.",
>                       semaphore.CurrentCount);
>     // Main thread waits for the tasks to complete.
>     Task.WaitAll(tasks);
>  
[/code]

となっています。ここで初めて`SemaphoreSlim.Wait()`が通過できるようになります。しかし、質問のコードは肝心のこの部分が省略されてしまっています。


CC BY-SA 4.0
2022-11-06T06:10:35.713
92027
2022-11-06T06:10:35.713
4236
92024
answer