С# взаимодействие потоков

228
29 марта 2018, 06:07

Как реализовать обмен данными между основным циклом и потоками? Допустим есть такой псевдокод Пример:

namespace First
{
    public class Test
    {
     public static string Outout1 = string.Empty;
     private static System.Threading.Thread SThread;
     public static string Func1() 
        {
               pass;
        }
     public static void GetTimeNow()
        {
           for(;;){
            Outout1 += Func1(); 
            System.Threading.Thread.Sleep(4000);
           }
        }
     public static string GetTimeNow2()
        {
             pass;
        }
        private static void RunThread()
        {
            if (SThread == null || SThread.ThreadState != System.Threading.ThreadState.Running)
            {
                SThread = new System.Threading.Thread(GetTimeNow);
                SThread.Start();
            }
        }
        public static void MainFunc()
        {
         for(;;){
         Outout1 +=  GetTimeNow2();
         RunThread() ;
         System.Threading.Thread.Sleep(5000);
         }         
        }
   }
}

Запускается главная функция MainFunc в бесконечный цикл в этом цикле вызываем функцию GetTimeNow2. Которая возвращает нам данные в переменную Outout1. Далее запускает функцию RunThread которая запускает функцию GetTimeNow в отдельном потоке.

В функции GetTimeNow бесконечный цикл, и в нем вызывается Func1, которая пишет данные в Outout1.

Вопрос будут ли всегда корректные данные в переменной Outout1, а именно будут ли видны данные от GetTimeNow2 и GetTimeNow и если обнулить ее в конце цикла она так же обнулится в GetTimeNow которая запущена в отдельном потоке? Пример:

 for(;;){
     Outout1 +=  GetTimeNow2();
     RunThread(); 
     System.Threading.Thread.Sleep(5000);
     Outout1 = "";
     } 

Подскажите пожалуйста как правильно реализовать данный способ , что бы можно было работать с переменной Outout1 как в основном цикле так и в цикле который запущен в отдельном потоке? и как сделать сделать если запустить не 1 поток а 2-5 Пример:

    for(;;){
     Outout1 +=  GetTimeNow2();
     RunThread(); 
     RunThread1(); 
     RunThread2(); 
     System.Threading.Thread.Sleep(5000);
     Outout1 = "";
     } 
Answer 1

Как один из вариантов - можно использовать асинхронное программирование с использованием ключевых слов async и await. Результат вы получите тот же без необходимости создавать потоки и без риска получить состояние гонки из за разделяемой переменной. Вот псевдокод:

public class MyTestClass
{
    public static string outputString = String.Empty;
    public static string GetFirstString()
    {
        return "world";
    }
    public static string GetSecondString()
    {
        return "!!!";
    }
    public static async Task FirstTimer()
    {
        for(int i = 0; i < 10; i++)
        {
            outputString += GetFirstString();
            await Task.Delay(50);
        }
    }
    public static async Task SecondTimer()
    {
        for (int i = 0; i < 10; i++)
        {
            outputString += GetSecondString();
            await Task.Delay(50);
        }
    }
    public static string GetStartString()
    {
        return "Hello ";
    }
    public static async Task MyMain()
    {
        for (int i = 0; i < 1 ; i++)
        {
            outputString += GetStartString();
            await FirstTimer();
            await SecondTimer();
            await Task.Delay(500);
            Console.WriteLine(outputString);
            outputString = String.Empty;
        }
    }

Проверить его можно или в UnitTest-е Например так :

    [TestMethod]
    public async Task TestAsyncLoop()
    {
        await MyTestClass.MyMain();
    }

Либо в консольном приложении

public static async Task Main()
{
    await MyTestClass.MyMain();
}

Примечание 1: в консольном приложении применить async к функции Main появилась только с версии компилятора C# 7.1 В других версиях компилятора нужно использовать

public static void Main ()
{
    MyTestClass.MyMain().Wait();
}

Примечание 2: в приложениях с графическим интерфейсом нужно использовать асинхронные методы с учетом контекста выполнения, что бы не попасть в состояние взаимоблокировки.

READ ALSO
Как работать с числами с плавающей запятой в С#?

Как работать с числами с плавающей запятой в С#?

Есть вот такой код простого конвертера валют(SOM - это валюта Кыргызстана)

207
c# WebBrowser Как при открытии сайтов игнорировать x-frame-options:?

c# WebBrowser Как при открытии сайтов игнорировать x-frame-options:?

При открытии сайтов должны игнорироваться x-frame-options (запрет на открытие некоторых страниц в iframe, в браузерах решается установкой мини-плагина)

206
Проект крашится после установки

Проект крашится после установки

Проблема следующая: создан проект wpf (с использованием фреймов и страниц)В отладке все стабильно работает, но после установки запускается...

205