Wątek przeniesiony 2023-01-04 12:42 z C/C++ przez Riddle.

Taski wewnątrz wątków

0

services.msc tworzy pętle w threadach:

foreach (DataRow dr in dt.Rows)
{
      int loopId = Convert.ToInt32(dr[0]);
      string threadName = "loop_" + loopId.ToString();
      Thread thread = new Thread(delegate () { MainLoop.RunLoop(loopId); });
      thread.Name = threadName;
      thread.Start();
      System.Threading.Thread.Sleep(100 * 1);
}

To działa dobrze, ale "RunLoop" używa tasków do http post:

var content = new StringContent(json, Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
string receiveStream;
var task = Task.Run(() => client.PostAsync(url, content));
task.Wait(); //task is null here
var response = task.Result;
httpRes = response.StatusCode.ToString();
receiveStream = response.Content.ReadAsStringAsync().Result;
receiveStream = receiveStream.Replace("\\/", "/");

Gdy uruchamiam ręcznie pojedyńczą pętlę wszystko działa okej - task nie jest nullem.
Gdy uruchamiam MainLoop z services.msc task ma wartość null (//task is null here) i mam błąd "odwołanie obiektu nie zostało ustawione na wystąpienie obiektu".

Nie mogę zrozumieć przyczyny problemu. Wygląda jakby thready się gryzły. Próbowałem przebudować taska na "async/await", ale to nie pomogło.
Z góry dziękuję za pomoc.

1

Tyle tu antypatternów, że głowa mała, ale jesteś pewien, że to task jest nullem?

Wyjątek, który dostajesz może pochodzić z akcji, którą wykonujesz w wystartowanym Tasku. Tak szczerze mówiąc, to nie widzę, jak task może być nullem, jak linijkę wcześniej go startujesz.

0

Dzięki za odpowiedź,
Po wystartowaniu Task program działa, potem trafia na task.Wait() i tam try-catch wyłapuje błąd:

System.AggregateException: Wystąpił przynajmniej jeden błąd. ---> System.NullReferenceException: Odwołanie do obiektu nie zostało ustawione na wystąpienie obiektu.

0
VanKiller napisał(a):

System.AggregateException: Wystąpił przynajmniej jeden błąd. ---> System.NullReferenceException: Odwołanie do obiektu nie zostało ustawione na wystąpienie obiektu.

Czyli tak jak się spodziewałem jest to wyjątek rzucony przez akcję wykonywaną w ramach odpalonego taska, a nie przez to, że task jest nullem.

Wygląda, że błąd masz w jakimś innym fragmencie kodu, bo takie coś:

using System.Net.Http.Headers;
using System.Text;

var client = new HttpClient();

foreach (var i in Enumerable.Range(0, 100))
{
    int loopId = i; /*Convert.ToInt32(dr[0]);*/
    string threadName = "loop_" + loopId.ToString();
    Thread thread = new Thread(delegate () { RunLoop(loopId); });
    thread.Name = threadName;
    thread.Start();
    System.Threading.Thread.Sleep(100 * 1);
}

void RunLoop(int loopId)
{
    var content = new StringContent("", Encoding.UTF8, "application/json");
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    string receiveStream;
    var task = Task.Run(() => client.PostAsync("https://jsonplaceholder.typicode.com/todos/1", content) );
    task.Wait(); //task is null here
    var response = task.Result;
    //httpRes = response.StatusCode.ToString();
    receiveStream = response.Content.ReadAsStringAsync().Result;
    receiveStream = receiveStream.Replace("\\/", "/");
}

co wydaje mi się jest odpowiednikiem tego co opisujesz, nie wyrzuca wyjątku.

0

Dzięki serdeczne! Problemu szukałem przy wielowątkowości i tasku, podczas gdy był on podczas inicjacji klasy non-static. Po prostu szukałem w złym miejscu, a przy deklaracji klasy był użyty parametr który istniał w wersji UI a nie było go w serwisie.
Problem rozwiązany, Pozdrawiam!

1

To teraz jeszcze:

  • pozbycie się niepotrzebnych blokujących operacji na asynchronicznych wywołaniach - .Result, .Wait(), zamiast tego powinieneś użyć async/await,
  • wywalenie Task.Run przy client.PostAsync, bo nic nie wnosi,
  • zamiana new Threadna Task.Run (w 99,99% przypadkach będzie lepszy od wykorzystywania gołego wątku)

I kod będzie znośny :P

1 użytkowników online, w tym zalogowanych: 0, gości: 1