Vlákna - vytváření a ukončení   zodpovězená otázka

C#, Threading

Dobrý den všem,

hledal jsem zde na portálu, ale nic jsem nenašel. Jak přesně fungují vlákna?

Pokud mám hlavní třídu, která nějakým způsobem běží. A v ní vytvořím vlákno (např. vlakno1). V tomto vytvořeném vlákně vytvořím další vlákno (např. vlakno2). A budu takto pokračovat třeba až do vlákna s názvem vlakno100. Žijou tyto vlákna svým vlastním životem závyslím pouze na hlavním vlákně, a nebo pokud zavřu některé vlákno, tak tím zavřu i vlákna, které v něm byly vytvořeny??

Dá se někde sledovat práce jednotlivých vláken? Pokud nemůžu použít zrovna Visual Studio.

Doufám, že sem to nsapsal aspoň trochu pochopitelně.

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

Životnost vlákna končí v momentě skončení jeho metody, jeho vynuceným ukončením metodou Abort, nebo ukončením programu (pokud jde o vlákno běžící na pozadí, jinak se aplikace neukončí). Visual Studio plně podporuje ladění vláken, slouží k tomu mimo jiné okno Threads (zobrazené při ladění).

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

Aha, takže jestli jsem tomu dobře rozumněl, tak to znamená, že každé vlákno si žije svůj život a pracuje do doby, než dojde do konce nějakého procesu. Neboli, pokud tam dám teoreticky cyklus while, kde odmínka bude neustále true, tak i když zavřu všechny ostatní vlákna, tak to jedno mi bude neustále pracovat a provádět operace uvnitř cyklu while - čistě teoreticky.

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

Vlákno je ukončeno po ukončení metody která ho "vyvolala".

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

Aha, tak se zeptám trochu jinak.

Řeším následující: Vytvářím jednoduchý server pro socketovou komunikaci a potřebuji obsluhovat více než jednoho klienta současně. Zpracovávání požadavků jednotlivých klientů řeším ve vláknech. Problém je, že potřebuji uchovávat předešlá data od jednotlivých klientů do doby, než dají příkaz k přeposlání dat. Server by měl běžet jako služba Windows. Nyní to mám řešeno následovně, spustí se služba, já nakonfiguruji server a spustím naslouchání, současně vytvořím nové vlákno, do kterého se připojuje klient, jakmile se klient připojí, tak vytvořím nové vlákno, do kterého se může připojit druhý klient, přičemž požadavky připojeného klienta zpracovávám ve vlákně, do kterého se daný klient připojil, atd. Jakmile se klient odpojí, tak ukončím jeho vlákno. A můj předpoklad byl, že pokud ukončím jedno vlákno pomocí metody Thread.CurrentThread.Abort(), tak že by vlákna, která jsem v tomto vlákně vytvořil měli běžet dál a až teprve, když ukončím všechny navazující vlákna, tak se ukončí i to, které jsem právě chtěl ukončit.

Chtěl bych se zeptat, jestli je tento postup správný, nebo bych měl zvolit nějaký jiný - například vytvářet vlákna v hlavní metodě.

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

Podle toho, píšete tak to správně je. Jen bych využil na zaúkolování vláken třídu ThreadPool, ta má optimalizace pro větší množštví vláken. Více na adrese: http://msdn.microsoft.com/en-us/library/...

Jinak na vyzkoušení je to určitě dobré, ale volil bych raději nějakou více abstraktní způsob vytvoření serveru, pokud to alespoň trochu půjde (webové služby, či WCF v IIS).

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

Problém je v tom, že kleinti nejsou schopni komunikovat pomocí HTTP protokolu, navíc je zde omezení ze strany délky dat.

Omezení jsou následující:

- je nutno použít socketovou komunikaci

- klienti nejsou schopni pracovat s HTTP protokolem

- délky dat odeslaných ke klientovy musí být konstantní

- a další, na které jsem zapomněl.

Proto jsem šel cestou vytvoření vlastního serveru.

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

Také bych se přikláněl k použití WCF, pracovat čistě se sokety je dnes již myslím pasé (kromě nějakých speciálních případů). WCF umí komunikovat i pomocí holého TCP protokolu a konfiguračním souborem (nebo programově) lze nastavovat všechny myslitelné věci (od komunikačního protokolu přes timeouty až po maximální velikost paketu). Je tedy pravda, že budete muset věnovat nějaký čas studiu toho WCF, protože to je skutečně velice komplexní věc.

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

Pokud jde o server pro menší počet klientů s nějakým opravdu primitivním protokolem a není čas (zadavatel není ochoten zaplatit za vývoj pod ověřeným řešením - WCF), tak je možné vlastní server využít. Jen je dost pravděpodobné, že zadavatel narazí na problémy a aplikace nebude 100% funkční a bezproblémová.

Na druhou stranu je pravda, že napsat si vlastní protokol pro WCF není banální záležitost a vyžaduje hlubokou znalost toho, jak celý WCF funguje.

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

Není potřeba vyvíjet vlastní kanál pro WCF, myslím že podstatné je, že ta komunikace bude čistě přes TCP (použije se už hotový TCP binding). Z hlediska high-level to bude vždy jen volání metod proxy třídy, jak bude probíhat low-level komunikace se nastaví v konfiguračním souboru (konkrétně zde tedy TCP).

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

To ano, ale podle toho co psal zadavatel, tak je protokol již určen a proto se defaultní TCP binding použít nedá:

Omezení jsou následující:

- je nutno použít socketovou komunikaci

- klienti nejsou schopni pracovat s HTTP protokolem

- délky dat odeslaných ke klientovy musí být konstantní

- a další, na které jsem zapomněl.

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

Postupně budu odpovídat na jednotlivé návrhy, názory a témata:

- WCF -> nevím, jak přesně pracuje WCF, ale já potřebuji čistě server, který běží jakožto služba ve Windows. Nebo-li pokud vypadne elektrický proud a dojde k restartu hardware, aby byl server funkční i bez zásahu člověka (přihlášení do windows a spuštění aplikace, atd.)

- Komunikace -> Defaultní TCP binding se nejspíše použít nedá, je to speciální aplikace, prostě je někde v budově například 100 klientů, kteří umí úplně primitivní komunikaci přes TCP, kdy já musím na každém klientovy přesně definovat jaká bude délka příchozích dat.

- protokol -> pro tyto účely byl vyvinut (téměř dva roky intenzivního vývoje) komunikační protokol nad TCP. V podstatě je to hodně, ale hodně, osekané HTTP. Jedná se o úplně základní komunikaci pomocí textových příkazů.

- 100% funkčnost -> jak jsem již psal, vývoj dané komunikace probíhal necelé dva roky, takže funkčnost je ověřena ze všech stran :-)

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

WCF je mimojiné řešení komunikace a protokolu. Jednotlivé "části" lze měnit. Jedná se o hotové řešení, na kterém běží celá řada systémů. Takže je zajištěna platforma se 100% funkčností. Také WCF prakticky nemá co dočinění se samotným spouštěním - to však může zajistit například IIS server nebo vlastní služba. Tak jako tak je hostování jednoduší a 100x bezpečnější a použitelnější než vlastní hostovač.

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

Zdravím,

takže je tu další problém, opět se to týká onoho serveru pro TCP socketovou komunikaci. Inspiraci jsem čerpal v článku o kreslící tabuly s přenosem dat pře TCP.

Situace je takováto, je hlavní vlákno, kde se spustí server a současně se spustí časovač. Jakmile časovač přeteče, program zkontroluje, jestli je přítomen požadavek na připojení (TcpListener.Pending()). Pokud je požadavek na připojení, tak se spustí nové vlákno, kde by to mělo přijmout dalšího klienta a začít s ním komunikovat. První připojení klienta není problém, první klient se bez problémů připojí a komunikuje, ale jakmile se pokusím připojit druhého klienta, tak nastane tato výjimka:

Type: System.IO.IOException; Message: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request.; Source: System; TargetSite: Int32 EndRead(System.IAsyncResult); StackTrace: at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)

at SIP.ThreadClient.CtiData(IAsyncResult ar);

Program provádí následující kroky:

TcpListener.BeginAcceptTcpClient()

TcpClient = TcpListener.EndAcceptTcpClient()

NetworkStream = TcpClient.GetStream();

NetworkStream.BeginRead();

... a jakmile dojde na NetworkStream.EndRead(), tak nahlásí výjimku a tváří se, jako by spojení bylo ukončeno, ale klient stále vydí tu komunikaci jako otevřenou a klidně může posílat data dál.

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

Tak jsem se to pokoušel přepsat do různých podob a výsledek je vždycky stejný. První klient se bez problémů připojí a posílá i přijímá data, ale jakmile se do toho připojí druhý klient, tak celá aplikace spadne a vyhodí výjimku. Jakoby přijetí prvního klienta nějakým způsobem dovolilo sice připojit dalšího klienta, ale jakmile se pokusí zaslat data, tak to ukončí celý server a znemožní další práci s ním. Napadla mě ještě otázka... je rozdíl mezi tím, když klienta přijmu v hlavním vlákně a nebo v dalším vlákně? No, nezbývá, než to zkusit, že? :-)

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

Použijte to WCF a nebudete muset řešit takové blbosti... WCF může být hostované ve službě a jako komunikační kanál může použít TCP takže není žádný problém. Jakmile do toho proniknete, nebudete litovat.

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

Bohužel, ale jsem teďkom v situaci, kdy se nemohu učit nové technologie/postupy, ale musím co nejdříve zjistit, kde je problém v současné podobě a odstranit ho. I když bych rád šel třeba jinou cestou (WCF, C++, ...), tak nejdříve musím zprovoznit server tak, jak je teďkom. V původním programu byla drobná chyba, v jednom místě, kam se program neměl dostat (aspoň dle mých chybných předpokladů), vězela smyčka. A jakmile se dostal do této části programu, tak začal vytěžovat CPU (4jádro 2.66Ghz) na 50-80% ... což nám začalo brzdit ostatní procesy na tomto serveru, proto musím co nejdříve najít chybu a odstranit ji, server jsem již několikrát celý přepsal, zkoušel různé varianty, ale stále stejný problém... a než bych pronikl do WCF tak, abych byl schopen napsat stabilní server, tak by to nějaký čas trvalo a ten já nemám. Bohužel, ale chyba se neprojevila během testování, ale až v ostrém provozu.

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

No, tak mám par otázek k tomu WCF, protože už jsem z toho docela bezradný... zjistil jsem, že je možno WCF aplikaci přidat do IIS jakožto rozšíření. Máte s tím nějaké zkušenosti ohledně funkčnosti? A další věc je, což jsem asi posledně neuvedl a je to stěžejní problém... server musí být schopen si pamatovat data z předchozí komunikace. Nebo-li ve chvíli, kdy se klient připojí, tak pro něj vytvoří nějaký buffer, do tohoto bufferu postupně ukládá data, která mu klient zasílá, současně klientovi vrátí odpověď o tom, že data přijal v pořádku. Po dokončení komunikace, veškerá tyto data odešle do databáze a klientovi vrátí konečný výsledek zápisu dat. A dříve, než se zeptáte, ne, není možné, aby klient veškerá data posílal současně. A ano, opravdu je musí uchovávat server. A ještě jednou ne, server nemůže data posílat rovnou do databáze, protože data jsou navzájem propojená určitými souvislostmi....

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

WCF lze hostovat v IIS, ve službě, nebo v obyčejné aplikaci. Bohužel s hostováním v IIS nemám žádné zkušenosti, nikdy jsem to nezkoušel. Teoreticky by ale tento způsob mohl mít nějaká omezení. Princip WCF je takový, že napíšete rozhraní pro komunikaci klienta se serverem, které potom implementujete jako třídu na serveru. Komunikace probíhá tak, že voláte metody té třídy (které mohou mít parametry a návratové hodnoty) a přenos dat probíhá transparentně (i s více klienty současně). S ukládáním dat do bufferu a následným odesláním do databáze nebude problém.

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

Zdravím, tak jsem začal pomalu zkoušet a experimentovat. Vycházím z tohoto článku http://www.codeproject.com/KB/WCF/WCFPar... a ze článků v dané sekci. Akorát bych měl pár otázek, zatím jsem se nedostal k tomu, abych někde v článku viděl odpovědi: Podle toho, co jsem zatím viděl, tak se s WCF komunikuje přes browser, samozřejmě předpokládám, že to lze i bez něho, ale spíše bych rád věděl, jestli se musí vždycky klient dotazovat jako by na nějakou "stránku"? Protože mám klienty, kde můžu zadat pouze IP asresu a port, nic víc. Prostě čisté TCP spojení.

Například v tomto kódu:

<configuration>
    <system.serviceModel>
        <services>
            <service name="FileServer.Services.FileRepositoryService">
                <endpoint name="" binding="netTcpBinding"
                    address="net.tcp://localhost:5000"
                    contract="FileServer.Services.IFileRepositoryService"
                    bindingConfiguration="customTcpBinding" />
            </service>
        </services>
        <bindings>
            <netTcpBinding>
                <binding name="customTcpBinding" 
                  transferMode="Streamed" 
                  maxReceivedMessageSize="20480000" />
            </netTcpBinding>
        </bindings>
    </system.serviceModel>
</configuration>

je adresa "net.tcp://localhost:5000", což mě docela mate... Možná vám moje otázka přijde dosti laická, ale raději se ptám, jestli to nemůže být problém, WCF neznám.

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

Komunikovat přes prohlížeč se rozhodně nebude (i když v prohlížeči lze zobrazit metadata dané služby). net.tcp je pouze označení bindingu (způsobu komunikace), který v tomto případě znamená, že služba WCF bude běžet na lokálním počítači pomocí TCP protokolu, na portu 5000. Tato informace je dost podstatná ve finálním nasazení, protože na stejné URI se budou připojovat i klienti WCF služby.

Ještě bych poznamenal, abyste si ohledně WCF nejdříve pečlivě nastudoval teorii jak to funguje a potom pokládal konkrétní dotazy.

Začít můžete třeba zde:

http://msdn.microsoft.com/en-us/library/...

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

No, stihl jste odepsat dříve, než jsem čekal. Radu beru v povědomí a již studuji.

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

takže jsem právě dočetl několik článků a tutoriálů k WCF. Následně bych řekl, že tento způsob komunikace není zrovna nejtěžší... i když z počátku to vypadalo docela šíleně :-)

Ale rád bych se zeptal na pár věcí (teda, spíše bych si rád pár věcí ujasnil).

1.) Pokud zvolím, že se má instance vytvářet "per session", tak to znamená, že v rámci jednoho připojení můžu uchovávat veškerá data, která mi klient pošle přímo v session, samozřejmě jen do doby, než se odpojí. A nebo budou dostupna i v případě, že by se znovupřipojil? Například klient ztratí připojení a připojí se znova.

2.) V těch příkladech, co jsem viděl bylo vždycky jen to, že service a klient byli WCF, ale nikde jsem neviděl příklad, jak ve WCF přijmout někoho, kdo nevyužívá WCF. Nebo přesněji, jak od něj přijmout zprávu. Napadlo mě jedině, že by se tedy musel vytvořit nějaký eventhandler a navázat ho na událost, kdy server něco přijme. A nebo je možno implementovat nějakou jinou cestou?

3.) Ve všech příklad byli klienti opět WCF aplikace, ale já mám klienty, kteří nemají OS ... žádný Windows, žádný Linux/Unix, žádný Mac OS... jsou to "jednoduché" stroje, jejíchž řídícím systémem je MCU, kde je všechno zadáno pomocí strojového kódu. I když nepochybuji, že by s tímto neměl mít WCF žádný problém, ale v žádném příkladu nebylo ukázáno, jak přijmou takového klienta (viz. bod 2).

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

Klienti i server samozřejmě musí být WCF, že na klientech není OS jste předtím nenapsal, tím pádem je pro vás WCF nepoužitelné.

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

Omlouvám se, nenapadlo mě, že by zrovna toto mohlo hrát nějakou zásadní roli. Takže tím pádem je WCF úplně pasé? On se můj problém jeví spíše tak, že je problém né v programu jako takovém, ale přímo v .NET-u na zařízení, kde je server programován...

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

Pokud není na klientech operační systém a jedná se o čistou TCP komunikaci, potom jsem přesvědčen, že je WCF pasé i v případě, že byste se pokusil vytvořit vlastní komunikační kanál.

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

no, s tím wcf je to stejně už jedno. Teďkom jsem se zaměřil čistě na směr C++. Akorát by mě zajímalo, jestli jste někdo nezažil případ, že by instalace nějakého programu či servise packu (jakákoliv instalace aktualizace zabezpečení) nějak poškodila knihovny .NET. PRotože mi pořád nejde do hlavy, jak je možné, že když jsem na stejném počítači před nějakou dobou vytvořil server, tak fungoval... ale když jsem ho na tom samém počítači vytvořil znova, tak se začal chovat takto divně.

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

Zdravím, tak se mi nakonec nepovedlo nějak rozumně rozchodit ono WCF, měl jsem problém se samotnými vzorovými příklady... vzal jsem vzorový příklad přímo z tutoriálu, přepsal ho do posledního písmenka (abych si nějak ošahal onu funkčnost WCF) a nic... dokonce ani Visual Studio mi nechtělo danou službu najít, nahlásilo mi to stejnou chybu jako předtím ten server.

Tak jsem nakonec už z čisté bezradnosti sáhl po tom, co jsem už trochu znal... a to C++... a nemohu si toto rozhodnutí vynachválit. To, co mi dělalo velké problémy v C#, .NET a WCF mi pod C++ fubguje bez problémů.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • 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