Esileht > Uncategorized > Rööpülesannete katkestamine

Rööpülesannete katkestamine


Rööpülesanded jooksevad üksteisest sõltumatult. Kui ühes ülesandes visatakse erand, ei takista see teistel ülesannetel edasi jooksmast. Erandid kogutakse kokku ja jõuavad pealõime.

Vaata seda näidet ühest kasutust programmist, kus iga lõim viskab poole täitmise pealt erandi:

static void Do()
{
  for (int i = 0; i < 100; i++)
    if (i >= 50)
      throw new OperationCanceledException();
}

static void Main(string[] args)
{
  try
  {
    Parallel.Invoke(Do, Do, Do);
  }
  catch (AggregateException x)
  {
    Console.WriteLine(x.InnerExceptions.OfType<OperationCanceledException>().Count() + " tasks canceled");
  }
}

Kõigi lõimede erandid kogutakse pealõime erandisse AggregateException. Ja selle InnerExceptions sisaldab meie näites täpselt sama palju erandeid nagu oli lõimesid. See tähendab, et iga lõim tegi oma tööd teistest sõltumatult ja jõudis oma tööga erandini.

Mida teha siis, kui üks lõim peaks saama teiste tegevuse katkestada? Näiteks, kui töös selgub viga, mis teeb mõttetuks kõigi teiste lõimede edasised pingutused. Teine variant on see, et kasutajal on “Loobu” nupp, millel klõpsates ta saab töö katkestada.

Siin tuleb appi CancellationTokenSource, mis on lõimeturvaline, spetsiaalselt selleks otstarbeks loodud objekt.

Meie järgmises näiteks on meil üldkasutatav muutuja

static CancellationTokenSource ts = new CancellationTokenSource();

ja igaüks (suvaline lõim või ka näiteks kasutaja, kes vajutab mingit nuppu) võib välja kutsuda ts.Cancel().

Ülesandeid luues on vaja kaasa anda Token:

Task.WaitAll
(
  Task.Factory.StartNew(Do, ts.Token),
  Task.Factory.StartNew(Do, ts.Token),
  Task.Factory.StartNew(Do, ts.Token)
);

Protseduur Do kasutab spetsiaalset meetodit ThrowIfCancellationRequested, mis kontrollib, kas ülesanded ei ole globaalselt katkestatud ja viskab erandi kui on.

static void Do()
{
  for (int i = 0; i < 100; i++)
  {
    ts.Token.ThrowIfCancellationRequested();
    if (i >= 50)
      ts.Cancel();
  }
}

Ülaltoodud näite tulemuseks on, et kõik ülesanded jõuavad katkestatud seisu, ent need katkestatakse hetkel, kui ükskõik milline lõimedest jõuab poole peale.

Mõned märkused

ThrowIfCancellationRequested vajab ressursse ja reaalelus ei oleks mõttekas tsükli igas sammus seda välja kutsuda. Näiteks kui tegemist on pikkade ülesannetega ja kasutaja vajutab katkestusnuppu, piisaks sellest, kui katkestamiseks kuluks üks sekund. Iga lõim peaks siis sel juhul kontrollima katkestust kord sekundis.

Teine asi on see, et ThrowIfCancellationRequested poolt visatavat erandit ei tohiks töödelda ülesandesiseselt, muidu see info ei jõua pealõimeni. Pealõimel on sellest kasu, sest Task-objekti Status seatakse sel juhul seisu TaskStatus.Canceled, mitte TaskStatus.Faulted nagu muude erandite puhul. Sel eesmärgil edastatakse Token ka Task.Factory.StartNew-meetodile.

Advertisements
Rubriigid:Uncategorized
  1. Kommentaare veel pole.
  1. No trackbacks yet.

Lisa kommentaar

Kommenteerimiseks palun logi sisse, kasutades üht neist võimalustest:

WordPress.com Logo

Sa kommenteerid kasutades oma WordPress.com kontot. Logi välja / Muuda )

Twitter picture

Sa kommenteerid kasutades oma Twitter kontot. Logi välja / Muuda )

Facebook photo

Sa kommenteerid kasutades oma Facebook kontot. Logi välja / Muuda )

Google+ photo

Sa kommenteerid kasutades oma Google+ kontot. Logi välja / Muuda )

Connecting to %s

%d bloggers like this: