Úvod

1. díl - Úvod

Ondřej Linhart       22.05.2008       C#, VB.NET, Threading       15404 zobrazení

Úvod do vícevláknových aplikací.

Úvod

V dnešní době, kdy dvou i vícejádrové procesory jsou naprosto běžné by bylo škoda nevyužít tento potenciál. Koncept multithreadingu je znám už dlouho, ale není tomu tak dávno co vícejádrové procesory byly doménou pouze serverových systémů.

V oblasti vývoje aplikací v jazyce Visual Basic bylo poprvé možné plnohodnotně vyvíjet vícevláknové aplikace s příchodem Visual Basicu 7.0 (Visual Basic .NET) v roce 2002. Toto bylo obrovským přínosem pro Visual Basic vývojáře, kterým se tímto dostal do ruky mocný nástroj.

Co je to Thread (vlákno)?

Vlákno je posloupnost instrukcí, které můžou být zpracovávány současně s dalšími vlákny. Je to cesta jak rozdělit program do více paralelně (nebo pseudo-paralelně) běžících úloh.

Je třeba rozlišovat mezi pojmy vlákno a proces. Proces obsahuje jedno nebo více vláken. Vlákna uvnitř procesu mohou vzájemně sdílet stejná data, procesy nikoliv.

Co je to Multithreading (vícevláknové zpracování)?

Vícevláknové zpracování obecně funguje na principu rozdělování času - každému vláknu je přidělen určitý čas procesoru (jehož délka závisí například na prioritě vlákna) a po uplynutí procesor přepne na další vlákno. Přepínání mezi vlákny probíhá tak rychle, že máme dojem že vše běží současně. Velmi důležitý je fakt, že procesor se může přepnout na další vlákno uprostřed zpracování nějaké operace (v dalším kole se ve zpracování pokračuje tam kde se skončilo) a to je právě hlavní důvod k synchronizaci o které budu psát později. Systém který se stará o přidělování času vláknům se nazývá Scheduler (plánovač - pozor, neplést s programem Plánovač úloh). Jiný způsob dosažení vícevláknového zpracování je tzv. Multiprocessing (souběžné zpracování), který využívá všechny procesory v systému ke skutečně paralelnímu zpracování - máte-li dvě a více jader, můžete zpracovávat dvě a více úloh současně. Existují dva způsoby multithreadingu - preemptivní, kde čas přiděluje systém (běžně používaný způsob) a kooperační, kdy je na vláknu samotném aby předalo řízení dál (používalo se ve Windows 3.x).

Hlavní problémy při psaní vícevláknových aplikací

Race condition

Race condition je nežádoucí stav, ke kterému dochází v momentě, kdy jedno nebo více vláken přistoupí ke sdíleným datům zatímco jiné vlákno s těmito daty již pracuje. Tato sdílená data se nazývají kritická oblast, část programu která pracuje s daty v kritické oblasti a kterou je třeba dokončit jako celek se nazývá kritická sekce.

Deadlock

Noční můra každého programátora. Deadlock nastává v momentě, kdy dokončení operace A je podmíněno dokončením operace B a zároveň dokončení B je podmíněno dokončením A. Jinak řečeno A čeká na B a B čeká na A, program tedy uvázne v mrtvém bodě. Ve většině případů je to způsobeno nesprávným použitím synchronizačního objektu ReaderWriterLock, který se stará o uzamykání přístupu ke sdíleným datům pro jednotlivá vlákna. Najít a odstranit Deadlock je velmi obtížné, obzvlášť u rozsáhlých projektů.

Atomické operace

Atomickou operací nazýváme takovou funkci, u které je na 100% zaručeno, že bude dokončena jako celek a že systém nepřepne na jiné vlákno uprostřed jejího zpracování. Takové funkce můžeme najít ve třídě System.Threading.Interlocked a jedná se o základní operace jako sčítání, inkrementace a dekrementace čísel a záměna čísel.

Příklad

Následující příklad vícevláknového zpracování představuje konzolovou aplikaci, která plní pole o velikosti 10 000 000 prvků náhodnými čísly. Aby byl vidět rozdíl délky zpracování, provádí se plnění pole nejprve hlavním vláknem a potom dvěma vlákny současně. Vzhledem k tomu, že příklad má být co nejjednodušší, neřeším zde synchronizaci přístupu ke sdíleným datům (pole náhodných čísel) do kterého zapisují obě vlákna současně. Výsledky se mohou na různých hardwarových konfiguracích lišit a na jednojádrových procesorech může být zpracování jedním vláknem dokonce rychlejší.

Imports System.Threading
Module Module1
  'Pole pro naplnění náhodnými čísly (sdílená data)
  Private numbers(9999999) As Integer
  Sub Main()
    'Nastaví název hlavního vlákna programu
    '(potom je přehledně vidět v seznamu vláken při ladění)
    Thread.CurrentThread.Name = "Main"
    'Naplnit celé pole náhodnými čísly jen pomocí hlavního vlákna
    ProcessNumbers(New Integer() {0, 9999999})
    'Vytvoření dvou vláken které budou provádět metodu ProcessNumbers
    '(každé vlákno nezávisle na sobě)
    Dim numberProcessor1 As New Thread(AddressOf ProcessNumbers)
    Dim numberProcessor2 As New Thread(AddressOf ProcessNumbers)
    numberProcessor1.Name = "numberProcessor1"
    numberProcessor2.Name = "numberProcessor2"
    'Spuštění obou vláken s parametrem (počátek a konec plnění pole)
    numberProcessor1.Start(New Integer() {0, 4999999})
    numberProcessor2.Start(New Integer() {5000000, 9999999})
    Console.ReadKey()
  End Sub
  'Metoda pro naplnění pole náhodnými čísly
  '(musí odpovídat delegátu System.Threading.ThreadStart nebo
  'System.Threading.ParameterizedThreadStart)
  Private Sub ProcessNumbers(ByVal obj As Object)
    Dim t0 As Date = Date.Now
    'Přetypování z objektu na pole dvou čísel
    '(počátek a konec plnění pole)
    Dim indexes() As Integer = DirectCast(obj, Integer())
    Dim randomizer As New Random()
    For index As Integer = indexes(0) To indexes(1)
      numbers(index) = randomizer.Next(Integer.MinValue, Integer.MaxValue)
    Next
    Console.WriteLine(String.Format("{0}: {1:N0} ms", Thread.CurrentThread.Name, Date.Now.Subtract(t0).TotalMilliseconds))
  End Sub
End Module
Výstup ukázkového programu může vypadat takto:
Main: 1 563 ms
numberProcessor1: 1 094 ms
numberProcessor2: 1 328 ms

Znamená to, že zpracování jedním vláknem trvalo 1 563 ms a zpracování dvěma vlákny současně 1 328 ms (obě vlákna byla spuštěna téměř současně, takže je třeba vybrat větší hodnotu protože druhé vlákno skončilo dříve). Rozdíl je sice nepatrný, ale v případě že by se jednalo o mnohem náročnější výpočet než vytvoření náhodného čísla (například výpočet čísla Pi s vysokou přesností) by byl rozdíl daleko větší.

Co dál?

V dalším díle seriálu bych se chtěl věnovat především problému synchronizace, ale rád uvítám veškeré vaše návrhy co byste chtěli vědět ohledně vícevláknového zpracování.

 

hodnocení článku

4 bodů / 4 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

1. Úvod 22.05.2008

 

Mohlo by vás také zajímat

Jednoduchý scheduler v .NETu

Asi to znáte – máte nějaký složitější systém na zpracování velkého objemu dat a čas od času potřebujete vykovat nějakou automatizovanou údržbu – typicky smazat všechny položky starší než několika dní. Možností, jak toho dosáhnout, je hodně. Snažil jsem se vymyslet něco jednoduchého a efektivního.

Hledáme .NET vývojáře (Praha, Brno, Frýdek-Místek)

Visual Studio 2017, .NET Core a nový formát projektů

 

 

Nový příspěvek

 

Diskuse: Vícevláknové aplikace

Nešlo by prosím v článku opravit okno kódu, aby se dalo snáze přečíst.

Je to sice nedůležitý detail, ale jak je to jednobarevné, tak se v tom špatně orientuji :)

Děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Radšej by som sa dočkal druhého dielu .......

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Stačí si zkopírovat do Visual Studia...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vícevláknové aplikace

Zdravím :)

Mám možno trochu hlúpu prosbu (som na webe VB), ale nemohli by ste uviesť uvedený príklad aj v jazyku C#?

Dik ;)

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

using Microsoft.VisualBasic;

using System;

using System.Collections;

using System.Collections.Generic;

using System.Data;

using System.Diagnostics;

using System.Threading;

static class Module1

{

//Pole pro naplnění náhodnými čísly (sdílená data)

private static int[] numbers = new int[10000000];

public static void Main()

{

//Nastaví název hlavního vlákna programu

//(potom je přehledně vidět v seznamu vláken při ladění)

Thread.CurrentThread.Name = "Main";

//Naplnit celé pole náhodnými čísly jen pomocí hlavního vlákna

ProcessNumbers(new int[] {

0,

9999999

});

//Vytvoření dvou vláken které budou provádět metodu ProcessNumbers

//(každé vlákno nezávisle na sobě)

Thread numberProcessor1 = new Thread(ProcessNumbers);

Thread numberProcessor2 = new Thread(ProcessNumbers);

numberProcessor1.Name = "numberProcessor1";

numberProcessor2.Name = "numberProcessor2";

//Spuštění obou vláken s parametrem (počátek a konec plnění pole)

numberProcessor1.Start(new int[] {

0,

4999999

});

numberProcessor2.Start(new int[] {

5000000,

9999999

});

Console.ReadKey();

}

//Metoda pro naplnění pole náhodnými čísly

//(musí odpovídat delegátu System.Threading.ThreadStart nebo

//System.Threading.ParameterizedThreadStart)

private static void ProcessNumbers(object obj)

{

System.DateTime t0 = System.DateTime.Now;

//Přetypování z objektu na pole dvou čísel

//(počátek a konec plnění pole)

int[] indexes = (int[])obj;

Random randomizer = new Random();

for (int index = indexes[0]; index <= indexes[1]; index++) {

numbers[index] = randomizer.Next(int.MinValue, int.MaxValue);

}

Console.WriteLine(string.Format("{0}: {1:N0} ms", Thread.CurrentThread.Name, System.DateTime.Now.Subtract(t0).TotalMilliseconds));

}

}

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nevím jestli to bude fungovat.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vícevláknové aplikace

Tenhle seriál je sice staršího data ale když má jen 1 díl tak mě to nutí se zeptat Bude další?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Bohužel se k dokončení tohoto seriálu již asi nedostanu. Možná když zbude čas, zkusím s tím pohnout.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vícevláknové aplikace

Hezký den

nejsem profesionální uživatel .net či VB, ale chtěl bych uvést několik skutečností, které souvisí s aplikacemi, která používají vlákna. Čerpám z vlastností thread implementovaných na systémech Unixu, a předpokládám, že MS nevymyslel zcela něco nového a ve vlastním helpu VB MS nic bližšího neuvádí.

1. podle mne panuje omyl, že když vytvořím např. aplikaci pomocí vláken, která má např. uhodnout heslo, dojde ke brutálnímu zkrácení času. Omyl, neboť vlákna jsou OS UNIX a předpokládám, že tak funguje WIN, udržována pod procesem, který je vytvořil a tomuto procesu určuje strojový čas preemptivní multitasking, tzn. výsledný čas ovlivňuje to, kolik strojového času dostane rodičovský proces a tím pádem i jednotlivá vlákna. (A je-li multitasking chytře vyřešen, tak proces s vlákny dostává tolik strojového času, kolik mu může systém přidělit.) Dále vlákno tím, že je udržováno pod procesem, nemůže být přeneseno na více než jedno fyzické jádro procesoru. Pokud to vím, tak možnost přenosu vlákna mezi fyzickým jádry procesoru žádný OS nemá, neboť je to velice složitá věc. Pro urychlení práce na více jádrech slouží zcela jiné nástroje, pracující s procesy, jako je např. MPI - Message Passing Interface a to není součásti VB.

2. pravý účel vláken lze právě spatřit ve všech aplikacích typu klient - server, kdy na serveru obsluhují klienty právě samostatná vlákna. Proč? Nutno si uvědomit, že ať používám TCP či UDP a ať používám nějaký systém kontroly přenosu, pošlu-li data klientovi, musím čekat několik ms na jeho odpověď (i v TCP, kde se o přenos starají nižší vrstvy OSI, jsou mezi jednotlivými pakety na straně odesílatele pauzy). No a tu čekací dobu mohu použít pro práci s jiným klientem. Taky jak zaznělo v jednom příspěvku, je možno vlákna využít i u některých aplikací, které mohou využívat vlákna pro čtení a zápis souborů na pozadí, v době kdy uživatel s aplikací pracuje (např. textový procesor, prakticky stále hnípe, neboť bych chtěl několi vidět, jak stále buší do klávesnice rychlostí několik kilo znaků/s).

Nemám-li pravdu dle bodu č. 1. tak musím smeknout před MS.

Jarda

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vícevláknové aplikace

Pokiaľ Vás ešte zaujímajú návrhy alebo námety čo by mal obsahovať 2. diel logickým pokračovaním konzolovej aplikácie by bola komponenta Background Worker. V niektorých iných príspevkoch ktoré som si tu prečítal ste odporúčali používať samostatné vlákno napr. pri načítaní väčších súborov. To by bol podľa mňa ideálny ukážkový príklad. Načítanie a ukladanie údajov je jednou z najčastejšie používaných operácii. Možností je však oveľa vias.........

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Chcel som napísať "viac....."

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vícevláknové aplikace

Kdy bude dalsí díl??? Bude vůbec někdy??

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Ano bude, mám ho připraven a budu se ho snažit dokončit co nejdříve.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Už se opravdu nemůžu dočkat dalšího dílu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vícevláknové aplikace

Já bych se přidal také s jedním dotazem. V práci máme jednojádrová pentia s tím, že mají softwarovou simulaci druhého jádra (teď si za boha nemůžu vzpomenout jak se to jmenuje, ale předtím než se masově rozšířilo používání dvoujáder do osobních PC, používalo se to docela často). Je mi jasné že pokud má procesor jedno jádro, nemůže zpracovávat současně více úkolů. Ale zajímalo by mě, zda se tato simulace druhého jádra projeví nějákým zásadnějším způsobem do chodu vícevláknové aplikace. (předem podotýkám že mi není moc jasné jak tato simulace pracuje)

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Zřejmě máte na mysli Hyper-Threading. Není to žádná softwarová simulace, je to záležitost CPU (ovšem operační systém to musí podporovat). Tato technologie se sice nevyrovná dvoujádrovému procesoru, ovšem nárůst výkonu může být oproti klasickému jednojádrovému procesoru bez podpory HT 15-30%. To se samozřejmě v aplikacích podporujících vícevláknové zpracování projevit může. Pokud vás zajímá jak to funguje, přečtěte si o tom na Wikipedii nebo oficiálních stránkách Intelu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Uloha

Mame dva nezavisle programy

Program 1 =P1

Program 2 =P2

DataPro prenos mezi nezavislymi programy =DP

Vytvorim DP v (metodu navrhnete napr. glogalni pamet

mozna je i neco jineho)

V P1 zamknu pristup k DP P2

Naplnim DP programem P1 (P2 ceka nebo cyklicky testuje zamek)

V P1 odemknu pristup k DP a P2 zamkne pristup k DP P1

Tet muzu v P2 delat v DP co chci ,cist, zapsat jine data

(P1 pokud mezitim pozada o pristup chova se stejne jako P2,

ktery cekal nebo testoval zamek)

V P2 odemknu pristup k DP

V P1 zamknu pristup k DP P2

A tak dale . ...

Brzo zjstite ze cast P1 a P2 musi bezet v samostatnem vlakne aby takto programy komunikovaly s predavanim dat.

Na takovy typ ulohy ve vlaknech by me zajimala cilova ukazka.

S pozdravem Bob

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Když mi napíšete co má přesně dělat vlákno 1 a vlákno 2 se sdílenými daty tak zde rád uvedu kompletní příklad.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Trochu to upresnim.

1)Cil 1 navrnout DP (muzeme tak prenaset data mezi Px = P1 ,P2 ,... kde x=<1,x>

Pritom obecne Px muze byt jak ve VB.net tak C++, VB6 a podobne .

Pro priklad je vhodne zustat u vb.net)

DP bych ocekaval v RAM kvuli rychlosti prenosu,

pricemz se musi navrhnout zpusob jak programy Px nezavisle zjisti ,

ze DP existuje a pokud neexistuje tak ho prvni kery to stihne zalozi ostatni se jen

podileji

(nechci to presneji konkretizovat , protoze je mozne ,ze existuje

i reseni o kterem jsem netusil, abych Vas neovlivnil pri reseni.

Bezne by kazdemu programu mela stacit informace

o nazvu oblasti s jejiz pomoci zjisti pointer odkud muze manipulovat s daty.

Pokud jde o virtualni pamet pak kazdy z Px muze mit jiny pointer a presto ve vysledku smeruje do DP

Dale by mel vedet jaka je velikost oblasti DP v bytech

Dale by z nazvu zamku mel aktivovat objekt ktery zamek zajisti.)

2)V case prenosu ma jen jediny program pravo manipulovat s DP ostatni Px cekaji.

Co se tyka ukazky tak to zjednodusim

P1 bezny programek s oknem Textbox 'povoleno multiline

a tlacitkem Start s funkci prenes data

a tlacitkem Start1 s funkci vygeneruj , zobraz a prenes data vlaknem

a checkboxem ktery v pripade zatrzeni generuje vygeneruje , zobrazi a prenese data vlaknem v nejake frekvenci cyklu

data pro prenos

dim T() as date 'Je rozumne prenaset t v ticks t(0).ticks - delka 8 byte

'z ticku zpet t(0)=new date(ticky)

dim S() as string 'pozor na stringy v cili je jen pointer do pameti kde je odkaz dale

dim D() as double 'but to prenest jako bstring (pak pointer

dim L() as long 'ukazuje na data , pointer-4 ukazuje na 4byte ktere obsahuji delku )

dim I() as integer

dim B() as byte

dim Citac as long

sub init

dim N as integer=5

redim T(N)

redim S(N)

redim D(N)

redim L(N)

redim I(N)

redim B(N)

call Generuj

Call Zobraz

end sub

sub Generuj

'nejaka fce ktera naplni nahodne vsechna pole

'v praktickem pouziti to muzou byt data, ktere chceme z ruznych duvodu prenes do uplne

'jineho programu v nasem pripade pro P2

Citac=Citac+1

end sub

Sub Zobraz

'nejaka fce ktera zobrazi vsechny pole + citac v Textbox

end sub

spustim program po inicializaci programove nebo rucne v P1 vygeneruji pole+citac, zobrazim

a vytvorim vlakno ktere zajisti prenos do DP s ochranou zamku.

navrat z vlakna se da detekovat a zobrazit ze vlakno probehlo a s jakym uspechem

(je vice metod jak to zajistit callback si nechte radeji na pozdeji)

Program P2 prijemce

Na formulari stejne TextBox okno jako v P1

Spustim program

zalozim

dim Mcitac as long =0

zalozim vlakno ktere pocka na data v DP pokud

citac ve clakne <> Mcitac =dorazily nove data

data predam do bezne casti a indikuji ,ze data jsou nove k dispozici

(predani dat pro hlavni cast musim udelat tak ,aby nekolidovaly(taky drobny zamecek))

Mcitac= citac ve clakne

vlakno se vraci na zacatek, aby moho precist nove data z DP

hlavni cast

jsou nove data - ano - poznac ze prave ctu (zamecek) zobrazim data v TextBox odemknu zamecek

(pro jednoduchost tam dejme timer na rozpoznani proporku novych dat 100 ms)

Snad je to jednoduche pro priklad.

S pozdravem Bob

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pokud jsem to dobře pochopil, chcete navrhnout nějakou aplikaci, která by se starala o meziprocesovou komunikaci dvou Win32 aplikací včetně synchronizace. Předem vás upozorňuji, že Managed jazyk se na takovou úlohu absolutně nehodí. Práce s pointery ve VB.NET není vůbec a v C# pouze omezeně a psát to celé pomocí Win32 API by byla neskutečná práce. Toto je úloha vyloženě pro C++ a to se přiznám není můj parket. Jsem ochoten vám napsat ukázkovou aplikaci pokud se bude jednat o vícevláknové zpracování v rámci jednoho procesu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pochopil jste to velmi dobre. :)

Vb.net s pointery maka velmi dobre,

i s pametovym prostorem - jen to neni pekne zverejnene.

Protoze je to docela prakticke mezi programy si predavat data

myslel jsem, ze by to byla velmi pekne ukazka.

Je mi jasne ze je to vyzva. Vb.net toho umi hodne.

Je to na Vas ta vyzva oslovila.

Podobny sok jsem zazil ,kdyz jsem zjistil, ze se ve VB6 da

programovat a spustit aplikace psana ve zdrojovem kodu assembleru (nekdy se to muze hodit).

Pohraji si s tim zkusim to prevest do vb.netu

Pozn.

1)podivejte se na typ IntPtr. (umi vb.net pracovat s pointery)

2)drobny priklad

pridejte si do programu:

Imports System.Runtime.InteropServices

Dim BPole(100) As Double

Dim BM as IntPtr 'Pointer kam zapsat data

Marshal.Copy(BM, BPole, 0, BPole.Length)

zkopiruje Bpole od indexu 0 na misto v pameti od adresy BM

o delce BPole.Length*8 [Byte]; delka 1 [double]=8 [byte]

3)v Class Marshal muzete alokovat i prostor pameti a ten pouzit.

4)Popripade pouzit jak rikate API pro Kanal v pameti pres mapovani v pameti.

Private Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (ByVal hFile As Integer, ByVal lpFileMappigAttributes As IntPtr, ByVal flProtect As Integer, ByVal dwMaximumSizeHigh As Integer, ByVal dwMaximumSizeLow As Integer, ByVal lpName As String) As Integer

a pouzit Mutex pro informaci o zamku

Dim MMutex As System.Threading.Mutex

Dim KanalJmeno As String ="JmenoMutexu"

MMutex = New System.Threading.Mutex(False, KanalJmeno, False)

a dotazovat se pres zamky

Dim B1 As Boolean

Dim KanalmillisecondsTimeout As Integer = 2000

B1 = MMutex.WaitOne(KanalmillisecondsTimeout, False)

If B1 = True Then

'zamkl jsem DP muzu snim pracovat

'pracuji

Call MMutex.ReleaseMutex() 'Uvolneni zamku

Else

'behem 2 sekund jsem se k DP nedostal

End If

S pozdravem Bob

pak muzete cist

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ano, vím že jde ve VB.NET pracovat s typem IntPtr, ale ten je určen především pro účely Platform Invoke. Narozdíl od C# není práce s pointery ve VB.NET součástí jazyka a tudíž s nimi nelze provádět aritmetické operace.

Kopírování pole je daleko rychlejší pomocí Array.Copy (mimochodem vámi uvedený kód nefunguje, protože nemáte v BM zdrojovou adresu).

Alokovat prostor v paměti a následně ho použít (pomocí Marshal)... A můžete uvést nějaký příklad jak by s tím potom mohly pracovat ostatní procesy? Protože jinak je taková alokace zcela zbytečná.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

V prikladu BM mela byt cilova adresa.

Prominte dal jsem tam opacny smer: spravne Bpole do pameti BM

Marshal.Copy(BPole, 0, BM, BPole.Length)

'Aritmeticke operace

dim B1 as intptr

dim B2 as intptr

dim x as integer

'pointer+x

B2=new IntPtr(B1.ToInt32 + x) ' tuto blninu jsem hledal malem rok

nastudujte Api:

(ps:ve vb.net 2008 by mely byt i jine moznosti - tesil jsem se ze je znate :( )

pointer ktery Vas zajima:

New IntPtr(MMapAdr)

Private Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal lpName As String) As Integer

Private Declare Function MapViewOfFile Lib "kernel32" Alias "MapViewOfFile" (ByVal hFileMappingObject As Integer, ByVal dwDesiredAccess As Integer, ByVal dwFileOffsetHigh As Integer, ByVal dwFileOffsetLow As Integer, ByVal dwNumberOfBytesToMap As Integer) As Integer

MmapHandle = OpenFileMapping(Win32FileMapAccess.FILE_MAP_ALL_ACCESS, 0, MName)

MMapAdr = MapViewOfFile(MmapHandle, Win32FileMapAccess.FILE_MAP_WRITE, 0, 0, 0)

S pozdravem Bob

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jeste upresneni:

Private Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (ByVal hFile As Integer, ByVal lpFileMappigAttributes As IntPtr, ByVal flProtect As Integer, ByVal dwMaximumSizeHigh As Integer, ByVal dwMaximumSizeLow As Integer, ByVal lpName As String) As Integer

' dwMaximumSizeHigh =0 'Hornich 32 bitu MaximumSizeHight; =0 pro file <= 4 Gbyte

' dwMaximumSizeLow =MSize 'Dolnich 32 bitu MaximumSizeHight

MmapHandle = OpenFileMapping(Win32FileMapAccess.FILE_MAP_ALL_ACCESS, 0, MName)

If MmapHandle <= 0 Then

MmapHandle = CreateFileMapping(0, IntPtr.Zero, PAGE_READWRITE, B2H32, B1L32, MName)

End If

S pozdravem Bob

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Účelem tohoto článku není naučit se používat Win32 API pro Unmanaged zápis do paměti nebo meziprocesová komunikace Win32 aplikací...

Mimochodem řešit komunikaci více různých aplikací pomocí zápisu a čtení sdílené paměti mi přijde zbytečně komplikované a neefektivní. Daleko lepší a spolehlivější řešení bych viděl v jediné aplikaci, kde by funkčnost jednotlivých aplikací zajišťovala samostatná vlákna, nebo .NET Remoting/WCF/Named Pipes v případě samostatných aplikací.

A co máte na mysli těmi "jinými možnostmi"? Pokud vím, jsou ve VB 2008 nové následující věci:

- LINQ

- Zápis XML přímo v kódu

- Detekce datového typu podle vložené hodnoty

- Nový způsob inicializace komplexních objektů

- Anonymní typy

- Extension Methods

- Lambda Expressions

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Vícevláknové aplikace

Nakoľko sa zatial zaoberám iba teóriou tejto problematiky, rad by som v budúcich dieloch videl trochu podrobnejší popis System.Threading. Ani s príkladu som úplne presne nepochopil, čo ktorý zápis robí.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Mno nejsem profik, ale je patrne ze je definovana funkce ProcessNumbers ktera plni pole v rozsahu od - do nahodnymi cisly.

Pak v hlavni funkci je zavolana tato funkce na naplneni v intervalu od 0 do 9 999 999. To znamena generuje deset milionu nahodnych cisel a zapisuje je do pole.

Pozdeji je prikazem Dim numberProcessor1 As New Thread(AddressOf ProcessNumbers) nadefinovan objekt (nebo trida nebo co to je) jako novy thread (vlakno),to same i pro druhy proces (Dim numberProcessor2 As New Thread(AddressOf ProcessNumbers)).AddressOf podle me urcuje funkci ktera se timto pak spusti.

na dalsich dvou radcich jsou nove vytvorena vlakna pojmenovana...

No a na poslednich dvou radcich ridici funkce jsou tyto thready odstartovany, to znamena spustena funkce na naplneni pole nahodnymi cisly. Kazde vlakno ovsem plni pouze polovinu pole, a procesy probihaji temer od stejne chvile, takze by to melo byt rychlejsi na dvoujadrovem procesoru.

Me zajimaji spise tyto otazky. Bude zatez skutecne rozlozena mezi obe jadra procesoru (pripadne na serveru mezi oba procesory)? Nemuze se stat ze by aplikace zatizila jeden procesor 2x a druhy zustal volny? A pripadne jak poznam kolik jader procesor ma (pripadne kolik procesoru ma server?)

Kdyz bych planoval napriklad herni server ktery by melo obsazovat vice klientu (treba 200), je mozne rozdelit aplikaci napriklad na 200 threadu (pro kazdeho hrace)? Nebo musim programovat tak, abych vytvoril idealne presne tolik threadu kolik mam procesoru? To znamena ze u dvoujadroveho procesoru bych musel napsat aplikaci tak aby kazdy thread obsluhoval 100 klientu? Takze spis, bude prilis mnoho threadu velka zatez na CPU nebo to nevadi a rezie na obslouzeni tolika threadu neni tak vysoka?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Velmi dobré otázky!

To jak bude přidělen čas procesoru pro jednotlivá vlákna záleží na systému a na vlastnostech programu (priorita procesu a vláken, je-li aplikace v popředí nebo na pozadí a spousta dalších věcí). Není vyloučeno, že v určitém momentě nastane situace, kdy budou vlákna vašeho programu obsluhována všemi dostupnými procesory. Tudíž není vyloučeno, že by všechna jádra prvního procesoru byla přidělena vašemu programu, ovšem druhý procesor rozhodně nebude zahálet, protože mezitím bude obsluhovat ostatní procesy.

Mimochodem se dá nastavit, aby konkrétní jádro obsluhovalo v rámci procesu pouze konkrétní vlákno a říká se tomu Thread Affinity.

Počet procesorů zjistíte pomocí System.Environment.ProcessorCount. Je to součet všech jader všech procesorů, takže pokud máte např. dva dvoujádrové procesory, dostanete číslo 4.

Počet vláken v procesu je teoreticky neomezený, ovšem v ideálním případě budou zpracovávána pouze X současně (kde X je součet jader všech procesorů). Příliš mnoho vláken samozřejmě zvýšení výkonu nepomůže, spíše naopak.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Děkuji za odpovědi a za článek...

Proč sem se ptal, někde sem totiž viděl zdorjový kód jednoduchého HTTP serveru (nebo co to bylo zač) a tam při každém nově navazujícím spojení (připojující se klient k serveru) si server pro tohoto uživatele vytvořil nový thread. Pak v tom threadu spustil asynchronní čtení dat a jejich zpracovávání. Je jasné že u HTTP serveru se příliš mnoho klientů současně stahujících malé soubory nesejde, pokud webový server není příliš vytěžovaný, ale co například nějaký poštovní server (IMAP, POP3) nebo třeba FTP server nebo nejakej streamovací server? Tam pak lze předpokládat vyšší zátěž (streamováni souboru několika desítkám klientů (pokud pomineme fakt že tohle se většinou řeší přes UDP)). Není pak lepší nechat jen pár threadu (dva třeba) a v každém z nich spracovávat jen některé klienty (sudé jedno vlákno a liché druhé vlákno)?

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback