Discussione:
[ThreadStatic()]
(troppo vecchio per rispondere)
Marcello
2008-03-17 19:57:16 UTC
Permalink
Ciao a tutti,

una richiesta più teorica che altro.
E' a cavallo tra aspx e programmazione oo, spero che il thread non sia
considerato off topic.

Allora, c'è una bella proprietà statica del framework che è
raggiungibile via:

System.Web.HttpContext.Current.Request

All'interno di una pagina web questa classe statica risulta diversa per
ogni chiamata http, e mi chiedo come sia possibile.

Provando infatti un banale:

private static int x=0;
protected void Page_Load(object sender, EventArgs e)
{
x++;
Response.Write(x);
}

sempre all'interno di una pagina aspx, chiamate http diverse visulizzano
il medesimo progressivo.
Un problema potrebbe derivare da threads diversi che condividono le
stesse variabili statiche, eppure anche con:

[ThreadStatic()] private static int x=0;
protected void Page_Load(object sender, EventArgs e)
{
x++;
Response.Write(x);
}

tutti gli utenti visualizzano il medesimo progressivo. Ma se facciamo:

[ThreadStatic()] public static int x;
protected void Page_Load(object sender, EventArgs e)
{
x++;
Response.Write(x+" "+System.Web.HttpContext.Current.Request["x"]);
}

La pagina su firefox che richiede ?x=1 e quella su ie che richiede ?x=2
visualizzano il medesimo progressivo eppure valori di Request diversi.
Come è possibile? Come scrivere una classe che si comporti come
System.Web.HttpContext.Current.Request?

Grazie,
marc.
Raffaele Rialdi [MVP]
2008-03-17 21:07:38 UTC
Permalink
Post by Marcello
[ThreadStatic()] public static int x;
protected void Page_Load(object sender, EventArgs e)
{
x++;
Response.Write(x+" "+System.Web.HttpContext.Current.Request["x"]);
}
La pagina su firefox che richiede ?x=1 e quella su ie che richiede
?x=2 visualizzano il medesimo progressivo eppure valori di Request
diversi. Come è possibile? Come scrivere una classe che si comporti
come System.Web.HttpContext.Current.Request?
ThreadStatic dice che la variabile statica riceve un'istanza differente in
ogni thread.
Asp.net, di default, serve ogni richiesta client in un thread differente. E
questo ovviamente serve a dare migliore responsività al sito
Quindi la prima richiesta incrementa a 1 la risposta e poi gli somma 1.
risultato 2
La seconda richiesta incremente a 1 la propria istanza, somma 1, risultato
2.

Mi spiego il risultato diverso solo se hai abilitato aspcompat=true sulla
pagina, cioè che tutte le richieste per quella pagina vengono eseguite in un
unico thread.


BTW ti sconsiglio di usare questo sistema in asp.net in quanto dovresti
verificare cosa succede al riciclo del thread conservato nel thread pool.
Rischi di avere comportamenti assurdi.
Se vuoi condividere in modo comune a tutti usa Cache.
Se vuoi condividere per ogni utente usa Session oppure Cache usando come key
il prefisso SessionID + qualcosa.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-18 09:32:54 UTC
Permalink
Post by Raffaele Rialdi [MVP]
ThreadStatic dice che la variabile statica riceve un'istanza differente
in ogni thread.
Asp.net, di default, serve ogni richiesta client in un thread
differente. E questo ovviamente serve a dare migliore responsività al sito
Quindi la prima richiesta incrementa a 1 la risposta e poi gli somma 1.
risultato 2
La seconda richiesta incremente a 1 la propria istanza, somma 1,
risultato 2.
Mi spiego il risultato diverso solo se hai abilitato aspcompat=true
sulla pagina, cioè che tutte le richieste per quella pagina vengono
eseguite in un unico thread.
Ciao Raf, grazie per la risposta.
No, non ho abilitato nulla di nulla, ma forse VS fa qualcosa lui, non
saprei, io comunque osservo un progressivo comune.
Post by Raffaele Rialdi [MVP]
BTW ti sconsiglio di usare questo sistema in asp.net in quanto dovresti
verificare cosa succede al riciclo del thread conservato nel thread
pool. Rischi di avere comportamenti assurdi.
Si infatti, ma come dicevo la questione è teorica, non ne ho necessità
pratica. Non riesco a capiere cosa sia
System.Web.HttpContext.Current.Request
e come sia sviluppato e come eventualmente sviluppare un oggetto analogo.

Statico è statico, e fin qui ci siamo. [ThreadStatic] pare di no, visto
il comportamento diverso in fase di test.
Insomma, come si fa a scrivere una proprietà statica che risulti diversa
per ogni sessione [senza ovviamente usare gli oggetti Request e Session
:-)]? E' solo una curiosità, come han fatto a scrivere quella classe?

marc.
Raffaele Rialdi [MVP]
2008-03-18 09:58:29 UTC
Permalink
Post by Marcello
Ciao Raf, grazie per la risposta.
No, non ho abilitato nulla di nulla, ma forse VS fa qualcosa lui, non
saprei, io comunque osservo un progressivo comune.
Di default le richieste di client diversi vengono servite in thread
differenti.
Puoi verificare scrivendo su una label della pagina questo:
Thread.CurrentThread.ManagedThreadId

Se a due richieste vedi numeri diversi, significa che sono eseguite in
thread differenti.
Post by Marcello
Si infatti, ma come dicevo la questione è teorica, non ne ho necessità
pratica. Non riesco a capiere cosa sia
System.Web.HttpContext.Current.Request
e come sia sviluppato e come eventualmente sviluppare un oggetto analogo.
Request è solo un modo per prelevare i parametri postati dal browser (nel
tuo caso la querystring con x=1 o 2)
Post by Marcello
Statico è statico, e fin qui ci siamo. [ThreadStatic] pare di no,
visto il comportamento diverso in fase di test.
Il discorso non è così semplice:
- static è statico *solo* all'interno di un Application Domain. Cioè
un'istanza per ogni AppDomain
- se è ThreadStatic è relativo al thread, quindi un'istanza per ogni thread
Post by Marcello
Insomma, come si fa a scrivere una proprietà statica che risulti
diversa per ogni sessione [senza ovviamente usare gli oggetti Request
e Session :-)]? E' solo una curiosità, come han fatto a scrivere
quella classe?
Vuoi la sessione senza usare la sessione? curioso :)
La Session va solo usata con intelligenza non vista come un essere
diabolico.
SessionID è un numero univoco per ogni sessione di navigazione.
Per ogni SessionID hai una Session diversa, quindi puoi usare Session.

Se però vuoi usare Cache (che è comoda per la scadenza sulle dipendenze, e
molte altre belle cose) è sufficiente usare SessionID come prefisso
all'oggetto che vuoi tenere da parte.
Esempio:
- utente A mette in Cache un oggetto con key (SessionID + "x") ==> key =
"1234X", value = 1
- utente B mette in Cache un oggetto con key (SessionID + "x") ==> key =
"5678X", value = 1

Quindi , nonostante la Cache sia un oggetto condiviso tra tutti gli utenti,
se imposti la key con qualcosa di riservato della sessione (cioè il
SessionID) avrai oggetti differenziati per sessione. Chiaro?
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Matteo Migliore
2008-03-18 10:08:52 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Se però vuoi usare Cache (che è comoda per la scadenza sulle dipendenze, e
molte altre belle cose) è sufficiente usare SessionID come prefisso
all'oggetto che vuoi tenere da parte.
- utente A mette in Cache un oggetto con key (SessionID + "x") ==> key =
"1234X", value = 1
- utente B mette in Cache un oggetto con key (SessionID + "x") ==> key =
"5678X", value = 1
Quindi , nonostante la Cache sia un oggetto condiviso tra tutti gli
utenti, se imposti la key con qualcosa di riservato della sessione (cioè
il SessionID) avrai oggetti differenziati per sessione. Chiaro?
Aggiungo solo che la Session ha un tempo di timeout
piuttosto limitato normalmente mentre la Cache no,
quindi va fatto il clean degli oggetti messi in
Cache con chiave SessionId + Xxx alla scadenza della Session,
altrimenti occuperebbero risorse inutilmente, quindi tendenzialmente
come meccanismo sarebbe da evitare.
--
Matteo Migliore
Blog: http://blogs.ugidotnet.org/matteomigliore

"E' più facile unire le stupidità
che far collaborare le intelligenze."
Raffaele Rialdi [MVP]
2008-03-18 12:47:28 UTC
Permalink
Post by Matteo Migliore
Aggiungo solo che la Session ha un tempo di timeout
piuttosto limitato normalmente mentre la Cache no,
Il timeout la cache ce l'ha ma lo decidi programmaticamente (sopra parlavo
di scadenza e dipendenze)
Post by Matteo Migliore
quindi va fatto il clean degli oggetti messi in
Cache con chiave SessionId + Xxx alla scadenza della Session,
altrimenti occuperebbero risorse inutilmente, quindi tendenzialmente
come meccanismo sarebbe da evitare.
Non serve proprio grazie al meccanismo della Cache che ti consente di legare
SessionID + X ad un altro oggetto, come ad esempio (ma non necessariamente)
la session.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-18 10:28:43 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Vuoi la sessione senza usare la sessione? curioso :)
Ciao Raff,
ti ringrazio di nuovo ma non ci stiamo capendo.
Non voglio scrivere la sessione senza usare la sessione e uso
normalmente gli oggetti session, application, cache e compagnia senza
problemi. Ho un problema teorico però, che mi piacerebbe risolvere, così
per curiosità.
La domanda è, credo, a suo modo semplice. Come è scrittta la proprietà
System.Web.HttpContext.Current?

Come fa a essere diversa per ogni sessione, pure essendo statica? Come
dimostra il mio test il semplice threadstatic non basta. O meglio, a
parita di condizioni thread static fallisce mentre
System.Web.HttpContext.Current continua a funzionare correttamente.

Mi è venuto in mente di andare a spiare in mono come han scritto quella
proprietà, forse ne vengo a capo.

grazie comunque,
marc.

P.S.
Per la cronaca, ho testato:

[ThreadStatic()] public static int x;
protected void Page_Load(object sender, EventArgs e)
{
x++;
Response.Write(x + " " +
System.Web.HttpContext.Current.Request["x"] + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
}


ottenendo risultati che appaiono disarmanti, per non rire deliranti:

Firefox:
http://localhost/website10/?x=5

1 5 5
2 5 5
3 5 10 [!!!]
4 5 10
5 5 5 [!!!!!!]

IE:
http://localhost/website10/?x=10

6 10 5 [!!!!]
7 10 10 [!!!]
8 10 10
9 10 5

rimarc.
Raffaele Rialdi [MVP]
2008-03-18 13:25:36 UTC
Permalink
Post by Marcello
La domanda è, credo, a suo modo semplice. Come è scrittta la proprietà
System.Web.HttpContext.Current?
Current va a prendere l'istanza di HttpContext di quel particolare utente
(SessionID). Se hai i cookie di sessione (non quelli permanenti che sono
altra cosa) o usi gli url cookieless, il web server può ricollegare le tue
richieste e assumere che sei sempre lo stesso utente.
Diversamente non potrebbe perché http è stateless e quindi vedrebbe tre get
come se fossero di tre utenti differenti.

Una volta recuperato Current, Request ti da l'oggetto HttpRequest relativo a
quella richiesta in particolare, da cui prendere QueryString, Form, etc.
Post by Marcello
Come fa a essere diversa per ogni sessione, pure essendo statica?
Le due cose sono slegate. Se le due tue richieste nella stessa sessione
vengono servite su due thread differenti, avrai due istanze differenti di X.
Cioè la sessione non entra minimamente in gioco con il discorso static.
Post by Marcello
Come
dimostra il mio test il semplice threadstatic non basta. O meglio, a
parita di condizioni thread static fallisce mentre
System.Web.HttpContext.Current continua a funzionare correttamente.
ThreadStatic è solo ed esclusivamente riferito al thread e non al context o
alla session.
Post by Marcello
P.S.
[ThreadStatic()] public static int x;
protected void Page_Load(object sender, EventArgs e)
{
x++;
Response.Write(x + " " +
System.Web.HttpContext.Current.Request["x"] + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
}
http://localhost/website10/?x=5
1 5 5
2 5 5
3 5 10 [!!!]
4 5 10
5 5 5 [!!!!!!]
http://localhost/website10/?x=10
6 10 5 [!!!!]
7 10 10 [!!!]
8 10 10
9 10 5
La prima colonna indica che il valore è stato progressivamente incrementato
La seconda colonna è ovvia.
Nella terza colonna, 5 e 10 sono due managed thread differenti. Il runtime
ha potuto servire le prime due richieste sullo stesso thread, mentre la
terza ha cominiciato a servirla su un nuovo thread (preso dal thread pool).
E poi via così.

Il risultato che vedo io, sempre in asp.net è differente ... temo che tu
abbia qualcos'altro che da noia.
Io uso IIS (visto che Cassini serve tutto nello stesso thread).
La mia prima colonna ha una numerazione differente a seconda della seconda.
Esempio (scritto a mano da me per renderlo esplicativo):

1 5 5
2 5 5
1 5 10
3 5 5
2 5 10
...
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-18 13:47:46 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Current va a prendere l'istanza di HttpContext di quel particolare
utente (SessionID). Se hai i cookie di sessione (non quelli permanenti
che sono altra cosa) o usi gli url cookieless, il web server può
ricollegare le tue richieste e assumere che sei sempre lo stesso utente.
Diversamente non potrebbe perché http è stateless e quindi vedrebbe tre
get come se fossero di tre utenti differenti.
Ciao Raff, grazie ancora.
...mmm... perdona ma non riesco a visualizzare la cosa fino in fondo.
HttpContext è statico e accede alla proprietà statica SessionID. Ok, ma
il problema è ora spostato qui. La proprietà statica SessionID come fa a
scegliere tra tutte le chiamate in corso quale è la mia? Come fa,
essendo statica a capire CHI sta chiamando quella proprietà?
I bol di mono, alla voce System.Web.HttpContext.Current riporta:

"This property is a gross hack. It is used by applications that have not
passed the HttpContext class around and require access to it.

The routine internally uses a technique similar to thread local storage
to fetch the value which is slower than having this property available
as a parameter to your routines."

Non ho capito cosia sia esattamente "gross hack" ma non sembra un
complimento. :-D
Appena trovo il codice vedo di capirci qulcosa.
Post by Raffaele Rialdi [MVP]
Post by Marcello
Come fa a essere diversa per ogni sessione, pure essendo statica?
Le due cose sono slegate. Se le due tue richieste nella stessa sessione
vengono servite su due thread differenti, avrai due istanze differenti
di X. Cioè la sessione non entra minimamente in gioco con il discorso
static.
Si certo, ma come funziona?
Post by Raffaele Rialdi [MVP]
ThreadStatic è solo ed esclusivamente riferito al thread e non al
context o alla session.
Si chiaro, era solo un'idea possibile ma non funziona.
Post by Raffaele Rialdi [MVP]
Il risultato che vedo io, sempre in asp.net è differente ... temo che tu
abbia qualcos'altro che da noia.
Può essere benissimo, in ogni caso il mio test mostra che
Context.Current non sfrutta il ManagedId per capire con chi sta
dialogando poichè questa informazione è del tutto aleatoria. Deve usare
qualcosa d'altro, ma cosa?
Post by Raffaele Rialdi [MVP]
Io uso IIS (visto che Cassini serve tutto nello stesso thread).
Anch'io, IIS 7 su Vista Business, nel caso dei miei test.
Post by Raffaele Rialdi [MVP]
La mia prima colonna ha una numerazione differente a seconda della seconda.
1 5 5
2 5 5
1 5 10
3 5 5
2 5 10
Il tuo test, quantomeno, rende giustizia a [ThreadStatic()]

marc.

P.S.
marcelluszebra sono io, e ho ancora vari amici al bar! :-D

marc.
Domenico
2008-03-18 14:18:51 UTC
Permalink
Spesso il termine static crea confusione in quanto un contesto specifico
possiede un suo static che non ha niente a che vedere con altre applicazioni
che dispongono di campi che hanno un comportamento basilare di essere
static.

Cioè possono essere discorsi static paralleli e percio' non coinciliabili.
Infatti il concetto static in alcune situazioni sembra soffocare in
contraddizioni dovuti ad usi di classi particolari che hanno contesti
statici per concezione di funzionamento, di logicita' insomma di
progettazione.

Spero di non essere stato statico nella risposta.
Post by Marcello
Post by Raffaele Rialdi [MVP]
Current va a prendere l'istanza di HttpContext di quel particolare utente
(SessionID). Se hai i cookie di sessione (non quelli permanenti che sono
altra cosa) o usi gli url cookieless, il web server può ricollegare le
tue richieste e assumere che sei sempre lo stesso utente.
Diversamente non potrebbe perché http è stateless e quindi vedrebbe tre
get come se fossero di tre utenti differenti.
Ciao Raff, grazie ancora.
...mmm... perdona ma non riesco a visualizzare la cosa fino in fondo.
HttpContext è statico e accede alla proprietà statica SessionID. Ok, ma il
problema è ora spostato qui. La proprietà statica SessionID come fa a
scegliere tra tutte le chiamate in corso quale è la mia? Come fa,
essendo statica a capire CHI sta chiamando quella proprietà?
"This property is a gross hack. It is used by applications that have not
passed the HttpContext class around and require access to it.
The routine internally uses a technique similar to thread local storage to
fetch the value which is slower than having this property available as a
parameter to your routines."
Non ho capito cosia sia esattamente "gross hack" ma non sembra un
complimento. :-D
Appena trovo il codice vedo di capirci qulcosa.
Post by Raffaele Rialdi [MVP]
Post by Marcello
Come fa a essere diversa per ogni sessione, pure essendo statica?
Le due cose sono slegate. Se le due tue richieste nella stessa sessione
vengono servite su due thread differenti, avrai due istanze differenti di
X. Cioè la sessione non entra minimamente in gioco con il discorso
static.
Si certo, ma come funziona?
Post by Raffaele Rialdi [MVP]
ThreadStatic è solo ed esclusivamente riferito al thread e non al context
o alla session.
Si chiaro, era solo un'idea possibile ma non funziona.
Post by Raffaele Rialdi [MVP]
Il risultato che vedo io, sempre in asp.net è differente ... temo che tu
abbia qualcos'altro che da noia.
Può essere benissimo, in ogni caso il mio test mostra che Context.Current
non sfrutta il ManagedId per capire con chi sta dialogando poichè questa
informazione è del tutto aleatoria. Deve usare qualcosa d'altro, ma cosa?
Post by Raffaele Rialdi [MVP]
Io uso IIS (visto che Cassini serve tutto nello stesso thread).
Anch'io, IIS 7 su Vista Business, nel caso dei miei test.
Post by Raffaele Rialdi [MVP]
La mia prima colonna ha una numerazione differente a seconda della seconda.
1 5 5
2 5 5
1 5 10
3 5 5
2 5 10
Il tuo test, quantomeno, rende giustizia a [ThreadStatic()]
marc.
P.S.
marcelluszebra sono io, e ho ancora vari amici al bar! :-D
marc.
Marcello
2008-03-18 14:28:13 UTC
Permalink
Post by Domenico
Spesso il termine static crea confusione in quanto un contesto specifico
possiede un suo static che non ha niente a che vedere con altre
applicazioni che dispongono di campi che hanno un comportamento basilare
di essere static.
Cioè possono essere discorsi static paralleli e percio' non
coinciliabili. Infatti il concetto static in alcune situazioni sembra
soffocare in contraddizioni dovuti ad usi di classi particolari che
hanno contesti statici per concezione di funzionamento, di logicita'
insomma di progettazione.
Spero di non essere stato statico nella risposta.
Ciao Domenico,
assolutamente no, non sei stato statico :-D
concordo completamente sul fatto che il modificatore static è uno di
quelli che richiede più tempo per essere completamente digerito e di
quelli che da più adito a ambiguità e rischi di scivoloni.
Continuo a non capire però cosa faccia, dietro le quinte, la proprietà
static SessionId, un modo affinchè funzioni è appoggiarsi a qualche
informazione che identifichi per esempio il thread [che potrebbe essere
stato associato alla session Id in qualche altro punto dell'applicazione
dentro una collezione statica] ma, come si è visto, questo dato non è il
ThreadManagedId, ma allora cosa?

marc.
Raffaele Rialdi [MVP]
2008-03-18 14:43:10 UTC
Permalink
Post by Marcello
Continuo a non capire però cosa faccia, dietro le quinte, la proprietà
static SessionId, un modo affinchè funzioni è appoggiarsi a qualche
informazione che identifichi per esempio il thread [che potrebbe
essere stato associato alla session Id in qualche altro punto
dell'applicazione dentro una collezione statica] ma, come si è visto,
questo dato non è il ThreadManagedId, ma allora cosa?
Oltre a quanto ho scritto nell'altro post, riassumo alcune cose:

- static è solo un modo per definire l'accessibilità di una porzione di
*memoria*. In condizioni normali significa una istanza per AppDomain.
Cioè l'istanza è mantenuta nella zona dati dell'oggetto AppDomain

- ThreadStatic indica una istanza per ogni thread. Cioè il esister una
istanza in ciascun TLS, la zona dati privata di un thread.

- ManagedThreadId è il numero assegnato ad un thread (managed, non win32)
che è un contesto di esecuzione (e che con la memoria non ha nulla a che
fare).
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Raffaele Rialdi [MVP]
2008-03-18 14:27:01 UTC
Permalink
Post by Marcello
Ciao Raff, grazie ancora.
...mmm... perdona ma non riesco a visualizzare la cosa fino in fondo.
HttpContext è statico e accede alla proprietà statica SessionID. Ok,
ma il problema è ora spostato qui. La proprietà statica SessionID
come fa a scegliere tra tutte le chiamate in corso quale è la mia?
Come fa, essendo statica a capire CHI sta chiamando quella proprietà?
HttpContext.Current è una proprietà statica che restituisce una *istanza* di
se stessa.
Ogni volta che viene fatta una richiesta al webserver, viene costruita
un'istanza HttpContext che contiene tutto ciò che puoi vedere da MSDN (tra
cui la Request, cioè un'istanza di HttpRequest che contiene i parametri
passati via querystring).

Dicevamo che http è disconnesso e stateless per natura. Ciò impedisce (a
livello di protocollo) di capire che due get di un browser siano
riconducibili alla stessa "navigazione".
Per ovviare a questo, viene inserito un header, il sessionid che il browser
si premunisce di restituire al webserver. Il webserver va in dictionary e
recupera sessione e compagnia bella.
Il sessionID è quindi una chiave univoca per ogni utente che sta navigando.
Post by Marcello
"This property is a gross hack. It is used by applications that have
not passed the HttpContext class around and require access to it.
È un hack in quanto nella stessa pagina, quando due utenti fanno
HttpContext.Current ottengono due istanze di HttpContext differenti,
relative cioè alla richiesta del browser.
Post by Marcello
The routine internally uses a technique similar to thread local
storage to fetch the value which is slower than having this property
available as a parameter to your routines."
Non ho capito cosia sia esattamente "gross hack" ma non sembra un
complimento. :-D
Appena trovo il codice vedo di capirci qulcosa.
I bol di mono fanno un ottimo paragone. Il TLS è *analogo* (non è la stessa
cosa) cioè è una zona dati privata e riservata di ciascun thread.
Post by Marcello
Post by Raffaele Rialdi [MVP]
Post by Marcello
Come fa a essere diversa per ogni sessione, pure essendo statica?
Le due cose sono slegate. Se le due tue richieste nella stessa
sessione vengono servite su due thread differenti, avrai due istanze
differenti di X. Cioè la sessione non entra minimamente in gioco con il
discorso
static.
Si certo, ma come funziona?
ThreadStatic mette nel TLS l'istanza di quella variabile, perciò tutto il
codice che viene eseguito in quel thread, accede sempre a quell'istanza di
var statica.

La sessione è decisamente trasversale. Cioè la sessione può girare una volta
in un thread e un'altra volta in un altro thread.
Post by Marcello
Si chiaro, era solo un'idea possibile ma non funziona.
Provalo in una console app che ti da meno problemi.
Thread t = new Thread(new ThreadProc(pippo))
oppure
ThreadPool.Queuexxx(new WaitCallback(pippo))

void Pippo(object param)
{
x++;
console.writeline( ....)
}
Post by Marcello
Può essere benissimo, in ogni caso il mio test mostra che
Context.Current non sfrutta il ManagedId per capire con chi sta
dialogando poichè questa informazione è del tutto aleatoria. Deve
usare qualcosa d'altro, ma cosa?
Sono proprio cose differenti, non so come dirtelo in altre parole.
- Context.Current mantiene i dati della get del browser
- ManagedThreadId è il numero del thread che sta eseguendo quel codice.
Trasversali e totalmente scorrelati tra loro
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-18 14:46:19 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Sono proprio cose differenti, non so come dirtelo in altre parole.
- Context.Current mantiene i dati della get del browser
- ManagedThreadId è il numero del thread che sta eseguendo quel codice.
Trasversali e totalmente scorrelati tra loro
Ciao Raff,

Mi spiace che non ci capiamo.
Si ho capito e benissimo.
Abbandoniamo Aspx.

lanciamo in due thread distinti i metodi:
Marcello
2008-03-18 14:58:27 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Sono proprio cose differenti, non so come dirtelo in altre parole.
- Context.Current mantiene i dati della get del browser
- ManagedThreadId è il numero del thread che sta eseguendo quel codice.
Trasversali e totalmente scorrelati tra loro
Ciao Raff,

Mi spiace che non ci capiamo.
Si ho capito e benissimo.
Abbandoniamo Aspx.

lanciamo in due thread distinti i metodi:

metodo1(1)
metodo1(2)

metodo1 è definito così:

public void metodo1(int x){
//Qui fa qualcosa
metodo2()
}

Problema, cosa mettere al posto di "//Qui fa qualcosa//" affinchè sia
possibile in metodo2 fare una cosa del tipo:


public void metodo1(int x){
x=ParametroIniziale;
}

e popolare x in un caso con il parametro iniziale 1 e nell'altro 2?
Una possibilità potrebbe essere:

[threadstatic()]int ParametroIniziale;
public void metodo1(int x){
ParametroIniziale=x;
metodo2()
}

ma questo non sembra il caso in discussione poichè esistono casi [e il
mio test lo dimostra] in cui threadstatic non funziona e la proprietà
request si.
Quindi come si fa?
Un'altra ipotesi potrebbe essere:

public int ParametroIniziale
{
get{return CollezioneDiParametri[ThreadId];}
set{CollezioneDiParametri[ThreadId]=value;}
}
public void metodo1(int x){
ParametroIniziale=x;
metodo2()
}

e questo funziona, anche il threadid fosse riutilizzato, non sarebbe un
problema, quindi forse il SessionId è recuperato con un meccanismo di
questo tipo.

Se così stanno le cose siamo, forse, al punto della faccenda. Come può
ThreadId essere statico? Una possibilità è che sia threadstatic e che
l'attributo a quel livello funzioni mentre nel mio test non funzioni per
qualche difficoltà, e sarebbe la cosa migliore perchè avrei raggiunto la
pace dei sensi :-D
Altrimenti credo che ThreadId debba fare qualcosa "fuori" dal framework,
ma non avrebbe senso chiamarlo "Managed"...

marc.
Marcello
2008-03-18 16:00:32 UTC
Permalink
Post by Marcello
Abbandoniamo Aspx.
Ok, credo di aver capito come può funzionare il gioco, e come farlo
funzionare se dovesse capita l'eccasione.

A IIS arriva una richiesta HTTP, si inizia il gioco:

ElaboraPagina(HTTPRequest)

All'inizio si crea il thread che elaborerà la pagina, contestualmente si
butta in una collezione statica l'id del thread e la session id:

private static CollezioneDiAssociazioniThreadIdSessionId<int, int>;
private void ElaboraPagina(HTTPRequest){

Thread t=new Thread();
CollezioneDiAssociazioniThreadIdSessionId[t.id]=HTTPRequest.SessionId;
Lancio il thread...
}
private static Context GetContext(sessionid){
Ritorna il context associato al session id passato
}
public static CurrentContext
{
get{return
GetContext(CollezioneDiAssociazioniThreadIdSessionId[CurrentThread.id];}
}

E tutto torna. Resta naturalmente il fatto di come CurrentThread possa
essere diverso per ogni thread ma pechè questo sia possibile basta che
una singola variabile threadid sia threadstatic, infatti, CurrentThread
potrò avere una struttura del tipo:

[trheadstatic] int currentthreadid;
public Thread CurrentThread
{
get{return GetThread(currentthreadid);}
}

E questo fatto curioso mostra come è molto saggio far si che
threadstatic sia un attributo e non un modificatore, infatti una volta
usato nell'unico punto come qua sopra, non serve più!
E CurrentThread può sempre essere usato come base per recuperare altre
informazioni, anche trasversali ai thread come la sessionid delle pagine
aspx.

Insomma, capisco che sia una regressione inutile o molto vicina
all'inutilità ma capirla è stato bello, restano naturalmente due curiosità:

1) Perchè a me sessionstatic non funziona [o funziona in modo inatteso]?
2) Il codice vero, dentro SessionId quanto sarà, nella realtà, simile a
quello ipotizzato?

mah, marc :-D
Domenico
2008-03-18 17:03:47 UTC
Permalink
Considera una cosa pero'... static non vuol dire condividere la variabile
tra piu' Thread. Il fatto che sia statica una variabile, o meglio un campo,
è relativa al contesto di elaborazione di quel thread. Piu' Threads che
accedono ad una variabile condivisa occorre sincronizzarla altrimenti cadi
in condizioni di errori quali blocco di threads e valori disattesi...
Il tuo dilemma sta nel capire la radice di un progetto di assegnazione di
numero di thread e di logica di creazione del numero di SessionID compresa
la sua gestione. Ma, i valori vengono inseriti in un contesto che non è piu'
statico bensi' accessibile tramite Classi pubbliche come quella del context.
Ogni thread possiede un suo stack, uno suo spazio di indirizzamento per vari
dati di variabili, chiamate di ritorno ecc... e questo gia' lo sai.
Tu vuoi praticamente creare un metodo di onnipotenza concorrenziale al
kernel del sistema di assegnazione degli ID ai singoli thread.

Considera che ThreadStatic è fondamentalmente una classe che deriva dalla
superclasse Attribute. Esaminando il codice di ThreadStatic si capiscono le
cose che cerchi.

Il metodo2 deve fare cio' che fa il metodo1 agendo su una variabile x
statica ? E' corretto finchè stai nello stesso contesto, altrimenti ci sono
forme di remoting da utilizzare per queste finalita'.

Alla fine ricordati che il framework è una logica strutturale di livello
alto, tu vuoi risposte di livello basso, cioè dietro le quinte come/cosa fa?

Mettiamoci d'accordo, scriveremo il motore .NET 4.0.... saremo
famosiiiiiiiiiiiiiiii

Se ho detto una ....beeppata.... ditemelo vuol dire che non ho capito
niente!!!
Voglio ritorna' al Commodore 64, sti static mi rendono stitic.
Post by Marcello
Post by Marcello
Abbandoniamo Aspx.
Ok, credo di aver capito come può funzionare il gioco, e come farlo
funzionare se dovesse capita l'eccasione.
ElaboraPagina(HTTPRequest)
All'inizio si crea il thread che elaborerà la pagina, contestualmente si
private static CollezioneDiAssociazioniThreadIdSessionId<int, int>;
private void ElaboraPagina(HTTPRequest){
Thread t=new Thread();
CollezioneDiAssociazioniThreadIdSessionId[t.id]=HTTPRequest.SessionId;
Lancio il thread...
}
private static Context GetContext(sessionid){
Ritorna il context associato al session id passato
}
public static CurrentContext
{
get{return
GetContext(CollezioneDiAssociazioniThreadIdSessionId[CurrentThread.id];}
}
E tutto torna. Resta naturalmente il fatto di come CurrentThread possa
essere diverso per ogni thread ma pechè questo sia possibile basta che una
singola variabile threadid sia threadstatic, infatti, CurrentThread potrò
[trheadstatic] int currentthreadid;
public Thread CurrentThread
{
get{return GetThread(currentthreadid);}
}
E questo fatto curioso mostra come è molto saggio far si che threadstatic
sia un attributo e non un modificatore, infatti una volta usato nell'unico
punto come qua sopra, non serve più!
E CurrentThread può sempre essere usato come base per recuperare altre
informazioni, anche trasversali ai thread come la sessionid delle pagine
aspx.
Insomma, capisco che sia una regressione inutile o molto vicina
1) Perchè a me sessionstatic non funziona [o funziona in modo inatteso]?
2) Il codice vero, dentro SessionId quanto sarà, nella realtà, simile a
quello ipotizzato?
mah, marc :-D
Marcello
2008-03-18 17:20:46 UTC
Permalink
Post by Domenico
Alla fine ricordati che il framework è una logica strutturale di livello
alto, tu vuoi risposte di livello basso, cioè dietro le quinte come/cosa fa?
Ciao Domenico,
no credo di no.
E' li il bello, SessionId, o Context.Current, o CurrrentThread non
funzionano con meccanismi "magici" o unsafe o esterni al fw. Si può fare
tranquillamente con gli strumenti offerti dal fw.
Cioè sono pezzi del fw che si possono riscrivere dentro il fw ed è
addirittura probabile che siano scritti interamente in c# managed.

Il comportamento così particolare di Context.Current.Request si può
riprodurre tranquillamente senza fare riferimento ad altre classi
statiche ma solo ed esclusivamente con codice proprio.

Non capivo come, ora credo di averlo capito. :-D

marc.
Domenico
2008-03-18 17:43:59 UTC
Permalink
Appunto! Un'architettura di livello alto da sempre la possibilita' di fare
chiamate all'indietro oppure di creare procedure di livello basso
utilizzando le caratteristiche del livello alto. Ma questo è una cosa voluta
eh! Non è coincidenza della progettazione programmatica.

Tuttavia la curiosita', l'interessamento ricorsivo di un sistema come il
.net frmwrk apre la mente, la soddisfazione di arrivo a capire un concetto
di quel tipo esaurisce lo stack mentale da dubbi. Ammiro la tua voglia di
indagare perchè anch'io sono cosi'... non mi accontento, a volte, di
prendere le cose per definizione. Forse perchè io provengo dal vecchio
Commodore 64 e solo un pazzoide come me poteva stamparsi 64KBytes di ROM
dove risiedeva il sistema Basic e quant'altro, solo per capire come faceva
il computer a distinguere i comandi in linea ecc...ecc....

E' importante capire la differenza tra public static e private static, per
esempio.
AAAAAAAAAAAAArgh!..... to be continued.
Post by Marcello
Post by Domenico
Alla fine ricordati che il framework è una logica strutturale di livello
alto, tu vuoi risposte di livello basso, cioè dietro le quinte come/cosa fa?
Ciao Domenico,
no credo di no.
E' li il bello, SessionId, o Context.Current, o CurrrentThread non
funzionano con meccanismi "magici" o unsafe o esterni al fw. Si può fare
tranquillamente con gli strumenti offerti dal fw.
Cioè sono pezzi del fw che si possono riscrivere dentro il fw ed è
addirittura probabile che siano scritti interamente in c# managed.
Il comportamento così particolare di Context.Current.Request si può
riprodurre tranquillamente senza fare riferimento ad altre classi statiche
ma solo ed esclusivamente con codice proprio.
Non capivo come, ora credo di averlo capito. :-D
marc.
Raffaele Rialdi [MVP]
2008-03-18 21:46:59 UTC
Permalink
Post by Marcello
Il comportamento così particolare di
Context.Current.Request si può riprodurre tranquillamente
senza fare riferimento ad altre classi statiche ma solo
ed esclusivamente con codice proprio.
Continuo a non capire perché tiri in ballo Request.
Request non fa altro che prendere dalla post http la tua query string, i
dati della form, etc. e metterli dentro un oggetto. Nulla, ma proprio nulla
di più.
Request è contestuale a quella specifica get/post del browser. Cioè nella
page_load vedi la tua querystring e non quella di un altro utente che sta
navigando il sito ... e mi pare ovvio.

Ma request con SessionID e lo specifico Thread su cui è serivita la
richiesta non c'entrano nulla.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com
UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog:
http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-19 09:14:59 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Continuo a non capire perché tiri in ballo Request.
Request non fa altro che prendere dalla post http la tua query string, i
dati della form, etc. e metterli dentro un oggetto. Nulla, ma proprio
nulla di più.
Ciao Raff, il problema non è della classe request, ma della proprietà
statica System.Web.HttpContext.Current.Request.
Affinchè questa possa prendere, come dici tu, la MIA query string deve
capire chi sono IO.
La domanda è, come fa? Un modo per farlo è quello che ho descritto,
associando il threadid al sessionid. E la cosa non genera nessunissimo
problema anche se il threadid viene riutilizzato, e questo è quello che
ho avuto difficoltà a capire ma che ora trovo proprio cristallino.
Se al lancio del thread qualche metodo associa il threadid al sessionid,
come mostrato negli esempi di pseudocodice che ho postato per tutto il
tempo in cui quel thread mi appartiene ho la possibilità di recuperare
tramite metodi statici il MIO sessionid e quindi la MIA query string, il
MIO Request, il MIO Response e così via.
Quello che è interessante è che questa possibilità non esiste con
tecniche "standard" ma è necessario che almeno un elemento della catena
sia ThreadStatic(). E qui sta il legame forte tra queste classi e i
thread. Un altro fatto estremamente interessante è che di ThreadStatic
ne è sufficiente 1, non ne servono, a logica, altri. Ma uno deve essereci.

marc.
Raffaele Rialdi [MVP]
2008-03-19 22:30:50 UTC
Permalink
Post by Marcello
Ciao Raff, il problema non è della classe request, ma
della proprietà statica
System.Web.HttpContext.Current.Request. Affinchè questa possa prendere,
come dici tu, la MIA
query string deve capire chi sono IO.
Questa è la cosa più facile da capire.
La Request è relativa all'attuale collegamento http. La connessione è
*aperta*, il client ha fatto una get/post, il server ha accettato la
risposta e la connessione è ancora attiva. Il web server ha quindi preso gli
header dalla connessione attiva e ha costruito un'istanza di HttpRequest che
è custodita dentro l'istanza di HttpContext che recuperi con la proprietà
Current.
Post by Marcello
La domanda è, come fa? Un modo per farlo è quello che ho
descritto, associando il threadid al sessionid. E la cosa
non genera nessunissimo problema anche se il threadid
viene riutilizzato, e questo è quello che ho avuto
difficoltà a capire ma che ora trovo proprio cristallino.
Non ha proprio senso dedurlo da un threadid. Quello viene pescato *a caso*
dal thread pool per permettere l'esecuzione del codice relativo a quella
request. Quel codice potrebbe girare dentro qualsiasi thread e il suo id non
è affatto predicibile (nè avrebbe senso che lo fosse)
Post by Marcello
Se al lancio del thread qualche metodo associa il
threadid al sessionid, come mostrato negli esempi di
pseudocodice che ho postato per tutto il tempo in cui
quel thread mi appartiene ho la possibilità di recuperare
tramite metodi statici il MIO sessionid e quindi la MIA
query string, il MIO Request, il MIO Response e così via.
Assolutamente no:
- Il tuo sessionID è scritto dentro gli header http
- La tua session viene recuperata da un dictionary che associa il tuo
sessionid all'oggetto session
- Il thread ID è casuale
- La tua query string così come request e reponse sono semplicemente
associati alla connessione attiva e funzionerebbero anche senza SessionID. A
riprova di questo la query string è recuperabile dalla tua request anche se
è la prima volta che ti colleghi al web server e quindi il sessionID non è
neppure stato ancora generato.
Post by Marcello
Quello che è interessante è che questa possibilità non
esiste con tecniche "standard" ma è necessario che almeno
un elemento della catena sia ThreadStatic(). E qui sta il
legame forte tra queste classi e i thread. Un altro fatto
estremamente interessante è che di ThreadStatic ne è sufficiente 1, non ne
servono, a logica, altri. Ma
uno deve essereci.
Il legame con i thread non c'è affatto e non ci può essere visto che il
thread su cui caschi è casuale.
A riprova di questo, se metti due web server con un dns round robin e
gestisci la session su sql server, tu continuerai a poter navigare la tua
webapp anche se le richieste avvengono un po' su un server e un po'
sull'altro server.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com
UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog:
http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-20 08:59:11 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Post by Marcello
Ciao Raff, il problema non è della classe request, ma
della proprietà statica
System.Web.HttpContext.Current.Request. Affinchè questa possa
prendere, come dici tu, la MIA
query string deve capire chi sono IO.
Questa è la cosa più facile da capire.
La Request è relativa all'attuale collegamento http.
Ciao Raff,
ma possibile che non ci capiamo? Le tue stesse parole sembrano darmi
ragione cercando di dimostrarmi che è sbagliato! :-D
Dici "La Request è relativa all'ATTUALE collegamento http"...
Non vedi che si continua a girare attorno allo stesso concetto?

La aproprietà statica CURRENT Request si basa sul collegamento http
CORRRENTE. Hai solo spostato il problema di 5 centimetri, come si
recupera da un metodo statico la connessione CORRENTE??
Post by Raffaele Rialdi [MVP]
La connessione è
*aperta*, il client ha fatto una get/post, il server ha accettato la
risposta e la connessione è ancora attiva. Il web server ha quindi preso
gli header dalla connessione attiva e ha costruito un'istanza di
HttpRequest che è custodita dentro l'istanza di HttpContext
Ok, ma HttpContext.CURRENT è statico quindi se lì dentro ci è stato
piazzata un'unica variabile statica tutti le decine di chiamate
concorrenti vedranno il medesimo valore. E invece no. Ognuno vede il
proprio di valore. Quindi il codice dentro HttpContext.CURRENT non può
essere:

private static Context mCurrent;

get{return mCurrent;}
set{mCurrent=value;}
Post by Raffaele Rialdi [MVP]
che recuperi
con la proprietà Current.
Si, ma io recupero il mio mentre un altro utente recupera il suo!!!
Post by Raffaele Rialdi [MVP]
Non ha proprio senso dedurlo da un threadid. Quello viene pescato *a
caso* dal thread pool per permettere l'esecuzione del codice relativo a
quella request.
Va benissimo un valore causale, e persino ripetuto, non è un problema. O
mostri una strada convincente diversa che permetta di scrivere un metodo
statico in grado di ritornare valori "personalizzati" a sessioni diverse
oppure bisogna dedurre che l'inizializzazione della risposta http inizia
associando il thread creato per quel compito ad una o più variabili in
modo da poterle poi recuperare staticamente.
Post by Raffaele Rialdi [MVP]
Quel codice potrebbe girare dentro qualsiasi thread e il
suo id non è affatto predicibile (nè avrebbe senso che lo fosse)
E' vero e va benissimo così!
Creo un thread e magari lo recupero pure riutilizzandone uno da un pool,
a quel punto il thread è MIO e resterà tale fino a chiusura del lavoro.
Associo a questo thread il MIO nome e cognome e in questo modo, durante
la vita della pagina potrò, dentro la pagina recuperare il mio nome e
cognome comn una proprietà statica del tipo NomeCognome.
Post by Raffaele Rialdi [MVP]
- Il tuo sessionID è scritto dentro gli header http
Preciso:
- Il tuo sessionID è scritto dentro I MIEI header http
che sposta solo il problema.
Post by Raffaele Rialdi [MVP]
- La tua session viene recuperata da un dictionary che associa il tuo
sessionid all'oggetto session
Si certo.
Post by Raffaele Rialdi [MVP]
- Il thread ID è casuale
Anche, non è un problema questo.
Post by Raffaele Rialdi [MVP]
- La tua query string così come request e reponse sono semplicemente
associati alla connessione attiva e funzionerebbero anche senza
SessionID. A riprova di questo la query string è recuperabile dalla tua
request anche se è la prima volta che ti colleghi al web server e quindi
il sessionID non è neppure stato ancora generato.
Non cambia nulla Raff, mi fa imbestialire non riuscire a descrivere
questo fatto così banale...
Post by Raffaele Rialdi [MVP]
Il legame con i thread non c'è affatto e non ci può essere visto che il
thread su cui caschi è casuale.
Questa non è una dimostrazione logica. Il fatto che il thread id sia
causuale e riutilizzato non dimostra affatto che non se possa fare niente.
Post by Raffaele Rialdi [MVP]
A riprova di questo, se metti due web server con un dns round robin e
gestisci la session su sql server, tu continuerai a poter navigare la
tua webapp anche se le richieste avvengono un po' su un server e un po'
sull'altro server.
Perdona ma queste considerazioni sono fuori tema...
Insomma, vediamo se ci capiamo su questo:
Tu dici "E' possibile scrivere il namespace System.Web senza usare mai
threadstatic()" io dico "Dal comportamento di
System.Web.HttpContext.Current si deduce che in qualche punto di
System.Web.HttpContext esiste un riferimento [interno o esterno] di
tipo threadstatic()".

marc.
Raffaele Rialdi [MVP]
2008-03-20 20:54:28 UTC
Permalink
Post by Marcello
Ciao Raff,
ma possibile che non ci capiamo? Le tue stesse parole sembrano darmi
ragione cercando di dimostrarmi che è sbagliato! :-D
Dici "La Request è relativa all'ATTUALE collegamento http"...
Non vedi che si continua a girare attorno allo stesso concetto?
Tu continui a cercare di legare il thread al sessionid e questo è totalmente
errato.
Post by Marcello
La aproprietà statica CURRENT Request si basa sul collegamento http
CORRRENTE. Hai solo spostato il problema di 5 centimetri, come si
recupera da un metodo statico la connessione CORRENTE??
[...]
Post by Marcello
Ok, ma HttpContext.CURRENT è statico quindi se lì dentro ci è stato
piazzata un'unica variabile statica tutti le decine di chiamate
concorrenti vedranno il medesimo valore. E invece no. Ognuno vede il
proprio di valore.
Un *metodo* statico è codice che ha *visibilità* delle *sole* istanze
statiche.
Quando istanzi tre oggetti, il *metodo* è sempre uno!!! Infatti il "this" è
il gancio che ti permette di vedere la zona di memoria specifica di
un'istanza.
Tu confondi *metodi* statici con *variabili* statiche.
Post by Marcello
Quindi il codice dentro HttpContext.CURRENT non può
private static Context mCurrent;
get{return mCurrent;}
set{mCurrent=value;}
Non è implementato così. L'istanza di HttpContext viene creata da asp.net e
passata all'appdomain di competenza via remoting.
In realtà dietro c'è remoting che effettua un passaggio di parametri
cross-appdomain con un meccanismo di Logical Thread che è tipico delle
chiamate di remoting.
Il logical thread non è un thread ma una zona dati che viaggia "out-of band"
cioè passa da un appdomain all'altro (anche tra pc remoti) insieme alla
chiamata in atto. In pratica sono dati di contesto della chiamata e infatti
viene spesso usato per passare i dati di autenticazione su remoting.
Quando la chiamata del runtime arriva a destinazione (l'appdomain corretto)
resta solo da mappare il sessionid presente nel context e recuperato dagli
header http, con la session (sempre che ci sia o non sia scaduta).
Post by Marcello
Post by Raffaele Rialdi [MVP]
che recuperi
con la proprietà Current.
Si, ma io recupero il mio mentre un altro utente recupera il suo!!!
Ci credo, ha la connessione aperta e quindi è banale capire quale sia. *Non*
è tenuta in una variabile ma costruita al volo dal runtime di asp.net e
passato via remoting. Infine tu la puoi recuperare tramite la proprietà
statica da remoting.
Post by Marcello
Va benissimo un valore causale, e persino ripetuto, non è un
problema. O mostri una strada convincente diversa che permetta di
scrivere un metodo statico in grado di ritornare valori
"personalizzati" a sessioni diverse oppure bisogna dedurre che
l'inizializzazione della risposta http inizia associando il thread
creato per quel compito ad una o più variabili in modo da poterle poi
recuperare staticamente.
Ripeto, il metodo statico non attinge da una var statica. Quando il canale è
aperto deposita nel _logical_ thread di remoting (assimilabile ad un
parametro passato tramite metodo) l'istanza di HttpContext che viene tenuta
da parte. Current è un modo conveniente per andare a prendere
quell'informazione che è sicuramente e solo tua (la recupera dal logical
thread di remoting aperto dal runtime di asp.net verso il tuo appdomain).
Post by Marcello
E' vero e va benissimo così!
Creo un thread e magari lo recupero pure riutilizzandone uno da un
pool, a quel punto il thread è MIO e resterà tale fino a chiusura del
lavoro. Associo a questo thread il MIO nome e cognome e in questo
modo, durante la vita della pagina potrò, dentro la pagina recuperare
il mio nome e cognome comn una proprietà statica del tipo NomeCognome.
Ok, bene. Ma nel tuo esempio tu associavi il sessionid al threadid e questo
non va bene. Era quello su cui non ero daccordo.
Se usi il threadid solo per la durata del ciclo di vita della richiesta, è
evidente che può essere usato.
Post by Marcello
- Il tuo sessionID è scritto dentro I MIEI header http
che sposta solo il problema.
Mettila come vuoi. Il sessionid è scritto dentro una zona di memoria (non
importa quale sia l'oggetto) che ti viene passata dal runtime di asp.net nel
tuo appdomain. Se il sessionid esiste nel dictionary allora sa anche se c'è
già una session pre-esistente, altrimenti viene trattato come un utente
nuovo.
Post by Marcello
Questa non è una dimostrazione logica. Il fatto che il thread id sia
causuale e riutilizzato non dimostra affatto che non se possa fare niente.
Guarda che io contesto solo il fatto di mantenere in modo indefinito la
corrispondenza tra threaid e sessionid.
Quando hai postato i risultati del tuo test, il cambio di threadid era
quello che ti contrariava vedi i "!!!" .... quando hai postato il codice
associavi threadid e sessionid, il che è fattibile solo per la durata della
singola chiamata, e di conseguenza questa associazione diventa inutile.
Post by Marcello
Perdona ma queste considerazioni sono fuori tema...
Tu dici "E' possibile scrivere il namespace System.Web senza usare mai
threadstatic()" io dico "Dal comportamento di
System.Web.HttpContext.Current si deduce che in qualche punto di
System.Web.HttpContext esiste un riferimento [interno o esterno] di
tipo threadstatic()".
Threadstatic in questo caso non viene usato e non avrebbe senso perché una
volta esaurita la richiesta quel thread perde di significato.
Questo è quello su cui insisto fin dall'inizio. NON puoi usarelo con asp.net
perché due richieste vanno su due thread a caso e la corrispondenza si
perde.

Threadstatic non potrebbe neppure essere usato per passare i parametri dal
runtime di asp.net alla tua webapp per il semplice motivo che
è necessario attraversare i confini dell'appdomain e le var statiche (anche
se non threadstatic) sono uniche solo nell'appdomain come dicevo fin dai
primissimi post.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Raffaele Rialdi [MVP]
2008-03-18 21:44:18 UTC
Permalink
Post by Domenico
Considera una cosa pero'... static non vuol dire
condividere la variabile tra piu' Thread. Il fatto che
sia statica una variabile, o meglio un campo, è relativa
al contesto di elaborazione di quel thread. Piu' Threads
che accedono ad una variabile condivisa occorre
sincronizzarla altrimenti cadi in condizioni di errori
quali blocco di threads e valori disattesi...
Aggiungo che il problema non è solo sulle var statiche ma anche su quelle di
istanza.
Se creo un oggetto A e lo passo a due thread T1 e T2, l'accesso
*all'istanza* A *deve* essere resa thread-safe.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com
UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog:
http://blogs.ugidotnet.org/raffaele
Raffaele Rialdi [MVP]
2008-03-18 21:41:49 UTC
Permalink
Post by Marcello
Ok, credo di aver capito come può funzionare il gioco, e
come farlo funzionare se dovesse capita l'eccasione.
ElaboraPagina(HTTPRequest)
All'inizio si crea il thread che elaborerà la pagina,
contestualmente si butta in una collezione statica l'id
private static
CollezioneDiAssociazioniThreadIdSessionId<int, int>;
private void ElaboraPagina(HTTPRequest){
Thread t=new Thread();
Non è così che fa asp.net .... è quello che vuoi fare tu? Non ha molto senso
legare un sessionid ad uno specifico thread e non è così che funziona il
thread pool.
Post by Marcello
CollezioneDiAssociazioniThreadIdSessionId[t.id]=HTTPRequest.SessionId;
Lancio il thread... } private static Context GetContext(sessionid){
Ritorna il context associato al session id passato
}
public static CurrentContext
{
get{return
GetContext(CollezioneDiAssociazioniThreadIdSessionId[CurrentThread.id];}
}
E tutto torna. Resta naturalmente il fatto di come
CurrentThread possa essere diverso per ogni thread ma
pechè questo sia possibile basta che una singola variabile threadid sia
threadstatic, infatti,
[trheadstatic] int currentthreadid;
public Thread CurrentThread
{
get{return GetThread(currentthreadid);}
}
Forse non ho capito io, ma non ci siamo per niente.

Se tu basi una scelta sul threadid, sbagli tutto perché i thread (quelli di
asp.net ma non solo) vengono presi da un threadpool, cioè riciclati e perciò
due utenti differenti possono ottenere lo stesso thread in momenti temporali
diversi.
Usare il threadid a questo scopo è assolutamente sbagliato.

Aggiungiamo ancora che l'uso qualsiasi tipo di variabile statica in asp.net
è una bomba a tempo. Non appena la webapp ricicla, l'application domain
viene buttato via e ripristinato in memoria, e quindi le var statiche sono
riazzerate. Quindi anche questo va buttato via.
Post by Marcello
E questo fatto curioso mostra come è molto saggio far si
che threadstatic sia un attributo e non un modificatore,
infatti una volta usato nell'unico punto come qua sopra,
non serve più!
ThreadStatic può benissimo essere un attributo perché c'è un clr che sa
quando tu ci accedi e quindi può decidere che fare.
Quello che fa il CLR con threadstatic è di controllare se nel thread che sta
accedendo allo static è già stata allocata quella var. Se non lo è la alloca
e la mette nel TLS altrimenti la riusa.
Un modificatore non avrebbe cambiato nulla, perché il CLR ha modo di capire
entrambi. A mio parere ha molto più senso un attributo per evitare che
questa opzione non fosse disponibile in altri linguaggi. Se infatti fosse un
modificatore di C#, anche F#, vb.net, Fortran.net etc. avrebbero dovuto
supportarla, cosa decisamente troppo costosa.
Post by Marcello
E CurrentThread può sempre essere usato come base per
recuperare altre informazioni, anche trasversali ai
thread come la sessionid delle pagine aspx.
Sbagliato. Il currentthread ogni volta può usare un thread differente,
accedere perciò ad un TLS differente e quindi totalmente dal risultato
imprevedibile.
Post by Marcello
Insomma, capisco che sia una regressione inutile o molto
vicina all'inutilità ma capirla è stato bello, restano
1) Perchè a me sessionstatic non funziona [o funziona in
modo inatteso]? 2) Il codice vero, dentro SessionId
quanto sarà, nella realtà, simile a quello ipotizzato?
Riprendiamo il concetto di thread. Un thread è un contesto di esecuzione e
ne esiste almeno uno in ogni processo che descrive lo spazio di
indirizzamento (0 ==> 2^32 per cpu a 32 bit). Nel mondo managed l'appdomain
costituisce una sorta di sub-processo ossia una sandbox in cui viene
confinato tutto ciò che può fare del codice... in parole povere ogni codice
managed che gira in un appdoman non può accedere ad un altro appdomain.

Ogni thread ha pieno accesso a tutto lo spazio di indirizzamento,
indipendentemente dall'appdomain. Il thread è quello che permette al codice
di essere eseguito ma non ha alcuna relazione con la memoria (la può
accedere tutta) a parte quella parte chiamata Thread Local Storage (TLS) che
è privata allo specifico thread.

Lo scheduler di Windows decide quale thread eseguire e su quale cpu/core
grazie ad una serie di parametri tra cui la priorità del thread.

Poiché creare thread e switchare da un thread ad un altro è un'operazione
*molto* costosa, esiste un serbatoio di thread chiamato ThreadPool che
conserva i thread anche dopo che hanno finito la loro vita (cioè la funzione
invocata sul thread è terminata).
Il ThreadPool ricicla i thread e li riutilizza secondo una politica del
tutto imprevedibile (per noi :-) ).

Asp.net si appoggia al threadpool per servire le richieste di un browser.
Per cui ad ogni get/post/... di un browser, asp.net prende un thread a caso
dal threadpool e gestisce la richiesta (ottenuta tramite
HttpContext.Current) che è *totalmente* scorrelata dal thread. Se premo F5
sul browser posso ricadere nello stesso thread come in un altro... è
casuale.

Viceversa il SessionID è creato la prima volta che un browser fa una
richiesta e viene messo negli header HTTP spediti al browser (il quale lo
rimanderà ad asp.net la volta successiva). Il SessionID lo puoi vedere con
Fiddler o qualsiasi altro sniffer.
SessionID è totalmente scorrelato dal thread in cui verrà processata la
richiesta del browser.... potrebbe anche essere eseguita in un appdomain
diverso (quando asp.net ricicla) oppure in un altro webserver (pc fisico) se
sei in una webfarm.

Tipicamente se la sessione non è inproc ma aspnet state server o meglio sql
server, puoi mantenere lo stato anche per anni. Cioè apri il browser, fai il
pieno con il carrello, vai in vacanza per un anno lasciando il pc acceso, e
poi premi F5 o continui a riempire il carrello. Non c'è nessun motivo per
cui non debba funzionare se il developer ha fatto bene il suo mestiere.


Sorry per lo sproloquio.
Se hai dubbi prova a postare un mini-esempio che riproduca il problema
perché dalle righe del precedente post non ho capito un gran che :)

Ciao!
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com
UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog:
http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-19 09:34:20 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Sorry per lo sproloquio.
Se hai dubbi prova a postare un mini-esempio che riproduca il problema
perché dalle righe del precedente post non ho capito un gran che :)
Ciao Raff,
per lo sproloquio non ci non problemi e dubbi ora proprio non ne ho.
Mi spiace non riuscire a mostrarti quello che era il mio problema e
quindi nemmeno quella che ora è una soluzione.

L'unica cosa è provare a riproporti il quesito originale:

Thread1 Lancia Metodo1(1);
Thread2 Lancia Metodo1(2);
Metodo1(x) Lancia Metodo2();
Metodo2 Chiama la variabile statica MioX;

In Thread1 MioX risulta valorizzato a 1, in Thread2 risulta valorizzato a 2.

Come scrivere il codice per ottenere questo scenario?

Risposta:
Non è possibile utilizzando solo i modificatori standard, da qualche
parte è NECESSARIO utilizzare l'attributo ThreadStatic()

Corollario 1:
Basta un solo attributo del tipo ThreadStatic().

Conclusioni:
Un attributo ThreadStatic è necessario e sufficiente per implementare lo
scenario descritto.

Corollario 1:
System.Web.HttpContext.Current è implementabile in c# [SOLO!] con la
tecnica descritta.

Dimostrazione:
Lo scenario in cui in PageLoad si accede a
System.Web.HttpContext.Current è identico a quello ipotizzato inizialmente.
Post by Raffaele Rialdi [MVP]
Ciao!
marc.
Raffaele Rialdi [MVP]
2008-03-19 22:44:18 UTC
Permalink
Post by Marcello
In Thread1 MioX risulta valorizzato a 1, in Thread2
risulta valorizzato a 2.
Come scrivere il codice per ottenere questo scenario?
Se vuoi che avere istanze differenti a seconda del Thread puoi usare TLS o
ThreadStatic (che alla fine sono la stessa cosa).
Ma devono essere thread su cui TU hai il controllo e NON presi dal thread
pool perché non puoi scegliere quale thread pescare dal pool.
Post by Marcello
Non è possibile utilizzando solo i modificatori standard,
da qualche parte è NECESSARIO utilizzare l'attributo ThreadStatic()
ok
Post by Marcello
Basta un solo attributo del tipo ThreadStatic().
ok, stessa cosa di sopra
Post by Marcello
Un attributo ThreadStatic è necessario e sufficiente per
implementare lo scenario descritto.
devi però aggiungere il "MA" che ho scritto sopra
Post by Marcello
System.Web.HttpContext.Current è implementabile in c#
[SOLO!] con la tecnica descritta.
Sbagliato! :) Non è così che funziona (vedi l'altro post)
Post by Marcello
Lo scenario in cui in PageLoad si accede a
System.Web.HttpContext.Current è identico a quello
ipotizzato inizialmente.
no,no,no ... L'istanza di HttpContext a cui accedi tramite current è
semplicemente derivata dalla connessione attiva.
Ci sono venti porte con venti utenti differenti con un numero in mano :), e
quando il web server apre la porta prende il numero direttamente dalla mano
dell'utente e costruisce un HttpContext. Stop! ... il thread su cui è svolta
questa operazione è del tutto ininfluente.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com
UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog:
http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-20 09:05:08 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Se vuoi che avere istanze differenti a seconda del Thread puoi usare TLS
o ThreadStatic (che alla fine sono la stessa cosa).
Ma devono essere thread su cui TU hai il controllo e NON presi dal
thread pool perché non puoi scegliere quale thread pescare dal pool.
Non è vero Raff,
va benissimo pescare un Thread dal pool, e poi inizializzarlo come
preferisco. Per il resto delle operazioni quel thread sarà "latore" di
informazioni ThreadStatic.
Post by Raffaele Rialdi [MVP]
Sbagliato! :) Non è così che funziona (vedi l'altro post)
L'ho visto l'altro post, ma non ci ho trovato un esempio di classe
statica che dia risultati diversi a sessioni diverse senza usare mai
threadstatic.
Post by Raffaele Rialdi [MVP]
no,no,no ... L'istanza di HttpContext a cui accedi tramite current è
semplicemente derivata dalla connessione attiva.
Ancora, "semplicemente derivata dalla connessione ATTIVA" hai spostato
la questione ma siamo sempre lì, come si determina in modo statico quale
sia la MIA connessione ATTIVA?
Post by Raffaele Rialdi [MVP]
Ci sono venti porte con venti utenti differenti con un numero in mano
:), e quando il web server apre la porta prende il numero direttamente
dalla mano dell'utente e costruisce un HttpContext.
Ottimo, come fa poi un metodo statico a dare a me il MIO context? Non è
più un metodo a cui passo il mio numerino:

System.Web.HttpContext.GetCurrent(int mionumerodifila);

Ma è statico!

System.Web.HttpContext.Current
Post by Raffaele Rialdi [MVP]
Stop! ... il thread
su cui è svolta questa operazione è del tutto ininfluente.
A mio avviso questo è falso e non è possibile ignorare completamente il
thread. Le informazioni statiche "personalizzate" possono solo essere
associate al thread corrente, oppure esistono altre tecniche che non
conosco ma che tu, d'altra parte, non mi citi :-D

marc.
Domenico
2008-03-20 12:05:08 UTC
Permalink
Secondo me neanche al parlamento europeo avrebbero cosi' discusso su uno
STATic ? ...Rendo la battuta ?...

Vorrei dire a Marcello che certamente esiste un handle che associa la
SessionID ecc...ecc... al Thread che poi elaborera' la pagina .asp

Alla fine a che te serve sape' come viene associato una SessionID al Thread
?

Inoltre, in riferimento al tuo codice puoi condividere la variabile X
utilizzando la classe Mutex, per esempio. Questi è piu' idoneo per gli
accessi alle risorse pero' il criterio basilare è lo stesso per tutte le
applicazioni di sincronizzazione.

---->
L'utente fa una richiesta di una risorsa Asp.Net tramite il browser. Il file
<nomefile>.aspx è una risorsa.
Esempio di richiesta: http://www.static.it/myStaticApp/myStaticPage.aspx
(ovviamente static è ironico nell'indirizzo eh?!)
Al software server IIS arriva la richiesta di static, una volta che è
arrivata la richiesta entra in gioco il driver http.sys del kernel di
windows. Il driver http.sys funge come vettore della richiesta http. Questi
viene consegnata al processo in modalita' User che esegue l'applicazione
web.
Tutte le richieste vengono inserite in un pool di thread. Il worker process
w3wp.exe è responsabile riguardo l'amministrazione delle richieste.
Sintetizzando, il worker process carica l'applicazione web compilata
(assembly), alloca un AppDomain. Quando l'applicazione viene eseguita essa
eredita (inherit) l'identita' del processo in funzione del settaggio fatto
nel web.config

Entra in gioco anche il runtime di Asp.Net. HttpRuntime.ProcessRequest viene
invocato, in questo momento viene creato un'istanza alla classe HttpContext.
Tale istanza è in essere pari alla durata della richiesta, quindi,
rappresenta la richiesta attuale. Tramite Context puoi accedere a Request,
Response, Application, Server ecc...eccc.... anzi pure alla Cache.
La classe Context, inoltre, puo essere utilizzata per memorizzare dati vari
e richiamarli.

Ogni richiesta ha un Context... giusto? Non è condivisa come dici tu!

Ho capito male quello che hai detto fino ad ora?
AlessandroD
2008-03-20 13:03:36 UTC
Permalink
Post by Domenico
Ogni richiesta ha un Context... giusto? Non è condivisa come dici tu!
Ho capito male quello che hai detto fino ad ora?
Mi intrometto chiedendo che qualcuno indichi come può essere implementata la
proprietà:

public static System.Web.HttpContext Current {public get; }

E' tutto qui il discorso: è una proprietà, quindi non riceve parametri che
la possano "aiutare" a far quel che deve, in più è statica, quindi per forza
può manipolare solo altri campi statici, anch'essi quindi comuni a *tutta*
la classe.
Bene, ora date queste premesse, come può essere che enne thread diversi
accedendo a Current ricevano indietro oggetti differenti?
Risposta di marc. e mia: la classe System.Web.HttpContext usa al suo interno
da qualche parte l'attributo ThreadStatic.
Risposta di altri? Se ce ne sono? :-)
--
Ciao, Alessandro

/*
Alessandro Dereani
Microsoft MVP - SQL Server
http://mvp.support.microsoft.com
*/
AlessandroD
2008-03-20 15:56:16 UTC
Permalink
Post by AlessandroD
Mi intrometto chiedendo che qualcuno indichi come può essere implementata
public static System.Web.HttpContext Current {public get; }
E' tutto qui il discorso: è una proprietà, quindi non riceve parametri che
la possano "aiutare" a far quel che deve, in più è statica, quindi per
forza può manipolare solo altri campi statici, anch'essi quindi comuni a
*tutta* la classe.
Bene, ora date queste premesse, come può essere che enne thread diversi
accedendo a Current ricevano indietro oggetti differenti?
Visto che è da poco che smanetto con il fw & parenti, mi permetto di postare
una sintesi del concetto a cui il thread fa riferimento (visto che, thread a
parte, con marc. si è passato abbastanza tempo dietro al messenger per
discutere su questa cosa), sintesi che almeno mi ha permesso di chiarirmi le
idee sull'argomento (almeno così mi pare.. :-)


Se in qualche modo viene garantito che di una classe A ne esista solo
un'istanza per thread, allora la classe A così definita:

public class A {
[ThreadStatic()]
static A _currentIstance;

public A (/* parametri vari del costruttore */) {
/* inizializzazione dell'istanza
...
... */

_currentIstance= this;
}

static public A Current {
get { return _currentIstance; }
}

/* Tutto il resto dell'implementazione
...
... */
}

Permette all'interno di ogni thread di accedere all'unica istanza della
classe A (unica per quel thread) semplicemente con:

/* Codice in qualsiasi punto ma all'interno dello stesso thread */
A.Current

Ciò è utile se, sempre a parità di thread, l'unica istanza della classe A
deve essere accedura da altri oggetti dello stesso thread perché offre
servizi/informazioni indispensabili.
Questi oggetti riescono ad avere accesso all'unica istanza della classe A
associata al thread proprio grazie alla proprietà statica Current.



Tutta sta roba continua ad essere vera anche tornando ad asp.net, visto che
anche se i thread sono riciclati, comunque uno stesso thread può servire
solo una richiesta in un certo momento, se più richieste sono servite
contemporaneamente per forza i thread sono più di uno e oguno ha il proprio
threadid che è univoco, quindi oguno avrà la propria copia locale della
variabile_currentIstance.
Perché marc. sulla sua macchina abbia quel comportamento anomalo (sembra che
l'attributo ThreadStatic sia ignorato se associato ad una variabile della
classe Page) è un mistero. Il fatto che pur con quel comportamento anomalo
comunque System.Web.HttpContext Current gli funzioni bene, marc. dice che
può dipendere dal fatto che il run-time di asp.net è comunque in forma già
compilata mentre la sua prova si basa su sorgenti compilati al momento. E mi
trovo daccordo con lui.
--
Ciao, Alessandro

/*
Alessandro Dereani
Microsoft MVP - SQL Server
http://mvp.support.microsoft.com
*/
Domenico
2008-03-20 16:31:38 UTC
Permalink
Secondo me questo attributo in ambito Asp.Net non ha alcun valore, nel senso
a che serve?
Post by AlessandroD
Post by AlessandroD
Mi intrometto chiedendo che qualcuno indichi come può essere implementata
public static System.Web.HttpContext Current {public get; }
E' tutto qui il discorso: è una proprietà, quindi non riceve parametri
che la possano "aiutare" a far quel che deve, in più è statica, quindi
per forza può manipolare solo altri campi statici, anch'essi quindi
comuni a *tutta* la classe.
Bene, ora date queste premesse, come può essere che enne thread diversi
accedendo a Current ricevano indietro oggetti differenti?
Visto che è da poco che smanetto con il fw & parenti, mi permetto di
postare una sintesi del concetto a cui il thread fa riferimento (visto
che, thread a parte, con marc. si è passato abbastanza tempo dietro al
messenger per discutere su questa cosa), sintesi che almeno mi ha permesso
di chiarirmi le idee sull'argomento (almeno così mi pare.. :-)
Se in qualche modo viene garantito che di una classe A ne esista solo
public class A {
[ThreadStatic()]
static A _currentIstance;
public A (/* parametri vari del costruttore */) {
/* inizializzazione dell'istanza
...
... */
_currentIstance= this;
}
static public A Current {
get { return _currentIstance; }
}
/* Tutto il resto dell'implementazione
...
... */
}
Permette all'interno di ogni thread di accedere all'unica istanza della
/* Codice in qualsiasi punto ma all'interno dello stesso thread */
A.Current
Ciò è utile se, sempre a parità di thread, l'unica istanza della classe A
deve essere accedura da altri oggetti dello stesso thread perché offre
servizi/informazioni indispensabili.
Questi oggetti riescono ad avere accesso all'unica istanza della classe A
associata al thread proprio grazie alla proprietà statica Current.
Tutta sta roba continua ad essere vera anche tornando ad asp.net, visto
che anche se i thread sono riciclati, comunque uno stesso thread può
servire solo una richiesta in un certo momento, se più richieste sono
servite contemporaneamente per forza i thread sono più di uno e oguno ha
il proprio threadid che è univoco, quindi oguno avrà la propria copia
locale della variabile_currentIstance.
Perché marc. sulla sua macchina abbia quel comportamento anomalo (sembra
che l'attributo ThreadStatic sia ignorato se associato ad una variabile
della classe Page) è un mistero. Il fatto che pur con quel comportamento
anomalo comunque System.Web.HttpContext Current gli funzioni bene, marc.
dice che può dipendere dal fatto che il run-time di asp.net è comunque in
forma già compilata mentre la sua prova si basa su sorgenti compilati al
momento. E mi trovo daccordo con lui.
--
Ciao, Alessandro
/*
Alessandro Dereani
Microsoft MVP - SQL Server
http://mvp.support.microsoft.com
*/
AlessandroD
2008-03-20 17:31:10 UTC
Permalink
Post by Domenico
Secondo me questo attributo in ambito Asp.Net non ha alcun valore, nel
senso a che serve?
Mi sa che serve, guarda, copio & incollo dal visualizzatore oggetti di VS:

public static System.Web.HttpContext Current {public get; public set; }
Membro di System.Web.HttpContext

Riepilogo:
Restituisce l'oggetto System.Web.HttpContext relativo alla richiesta HTTP
corrente.

Valori restituiti:
Oggetto System.Web.HttpContext per la richiesta corrente.

Sempre per via di quella benedetta Current.
Vedi, è una proprietà statica che ritorna un'istanza della stessa classe
dove lei è definita.
Assomiglia tanto all'esempio sulla classe A.

Ma in generale credo che se all'interno di un thread c'è bisogno di avere
accesso alle uniche istanze (unica per thread, perché concettualmente è
giusto così per il contesto in cui questo iter si applica) di un gruppo di
classi ecco che questo modo di operare si presta molto bene.
Hai in mano le istanze chiedendo direttamente alla classe, non serve da
nessuna parte creare esplicitamente queste istanze per poi passarle come
parametri in giro per i metodi.
--
Ciao, Alessandro

/*
Alessandro Dereani
Microsoft MVP - SQL Server
http://mvp.support.microsoft.com
*/
Marcello
2008-03-20 14:07:31 UTC
Permalink
Post by Domenico
Alla fine a che te serve sape' come viene associato una SessionID al
Thread ?
Ciao Domenico,

quasi a niente! :-D
diciamo che per usare una proprietà statica all'interno di pagine aspx,
una tecnica, e forse l'unica, è quella di inzializzare una variabile
threadstatic o legata a threadid e poi usarla, per esempio:

[threadstatic()] variabile;
Page_Preinit(){
variabile=Inizializzaione;
}
AltroMetodoSuccessivo(){
Qui uso la mia variabile statica
}

E la questione è solo teorica, non mi serve davvero, semplicemnte si può
scrivere una proprietà che si comporta come Context.Current e per farlo
ci si appoggia al thread corrente.

marc.
Domenico
2008-03-20 15:51:11 UTC
Permalink
Cioa Marcello,

la variabile statica restera' visibile e manipolabile se la richiesta fa
parte sempre di una stessa sessione di connessione al webserver.

Ogni richiesta tramite un browser aperto equivale a richieste con sessioni
differenti, come si condivide la variabile?

Io quello che non riesco a capire se il tuo intento è quello di staticizzare
una variabile e condividerla tra tutte le richieste di sessione diverse, in
quel caso occorre utilizzare le pipeline di http per eseguire un compito
simle, un handler.
Ti prego Marcello dimmi che sto in strada perchè sto male, ho il viso
statico (marmizzato!) davanti al mio pc.

N Threads ricevono lo stesso context su una stessa connessione. O mi
sbaglio?

Il ThreadStatic infatti è come un wrapper per quella variabile, è una classe
che gestisce gli accessi a X.
Post by Marcello
Post by Domenico
Alla fine a che te serve sape' come viene associato una SessionID al
Thread ?
Ciao Domenico,
quasi a niente! :-D
diciamo che per usare una proprietà statica all'interno di pagine aspx,
una tecnica, e forse l'unica, è quella di inzializzare una variabile
[threadstatic()] variabile;
Page_Preinit(){
variabile=Inizializzaione;
}
AltroMetodoSuccessivo(){
Qui uso la mia variabile statica
}
E la questione è solo teorica, non mi serve davvero, semplicemnte si può
scrivere una proprietà che si comporta come Context.Current e per farlo ci
si appoggia al thread corrente.
marc.
Raffaele Rialdi [MVP]
2008-03-20 22:52:07 UTC
Permalink
Post by Marcello
Non è vero Raff,
va benissimo pescare un Thread dal pool, e poi inizializzarlo come
preferisco. Per il resto delle operazioni quel thread sarà "latore" di
informazioni ThreadStatic.
Facciamo il discorso partendo alla rovescia.
L'handler della pagina è un handler asincrono. Quando HttpRuntime crea
un'istanza di HttpContext, non potrebbe mai passarlo sul thread perché non è
lo stesso thread. In più se guardi reflector usa (come dicevo nell'altro
thread) ILogicalThreadAffinative che è un modo per passare i parametri usato
da remoting. Probabilmente l'uso di remoting è proprio per gestire il
momento del riciclo in cui per un attimo esistono due appdomain per la
stessa webapp.

Da qui si evince ancora una volta che threadstatic non è un sistema usabile
da asp.net.
Post by Marcello
L'ho visto l'altro post, ma non ci ho trovato un esempio di classe
statica che dia risultati diversi a sessioni diverse senza usare mai
threadstatic.
Perché ho il vizio di lavorare :) e l'esempio richiede due porzioni di
codice: quella che emula il runtime di asp.net che riceve dal socket le
informazioni e le spedisce all'appdomain. E poi la seconda parte che
recupera queste info tramite una proprietà (non variabile!!!!) statica.

Ho degli esempi (che sono poi quelli che presento nelle sessioni) ma
ovviamente sono troppo lunghi da postare qui e richiedono un certo tipo di
attenzione nella compilazione perché hanno almeno tre assembly differenti.
L'esempio che ho in mente è quello di remoting con ILogicalThreadAffinative
che ho realizzato in un progetto ancora al tempo del fx 1.1.
Post by Marcello
Ancora, "semplicemente derivata dalla connessione ATTIVA" hai spostato
la questione ma siamo sempre lì, come si determina in modo statico
quale sia la MIA connessione ATTIVA?
La recuperi dal canale di comunicazione. Il discorso di fondo con la request
è che viene creata prima ancora di porsi il problema di chi sia o chi non
sia l'utente. Ad una richiesta del client viene creata una httpcontext,
questa viene passata tramite canale di comunicazione di remoting.
Post by Marcello
Ottimo, come fa poi un metodo statico a dare a me il MIO context? Non
System.Web.HttpContext.GetCurrent(int mionumerodifila);
Ma è statico!
System.Web.HttpContext.Current
E non vedo il problema. Tu passi dei dati, ma mica devono essere presenti
nella lista dei parametri della chiamata.
Se lavorassi nello stesso thread potresti usare il TLS, se condividi un ID
con la controparte, puoi usare un atom oppure leggere il dato da un
dictionary.
Asp.net usa un sistema usato da remoting quando deve passare i confini
dell'appdomain.
Probabilmente usa questo sistema per ovviare ai problemi che ormai ho
ripetuto alla noia su threadstatic
Post by Marcello
Post by Raffaele Rialdi [MVP]
Stop! ... il thread
su cui è svolta questa operazione è del tutto ininfluente.
A mio avviso questo è falso e non è possibile ignorare completamente
il thread. Le informazioni statiche "personalizzate" possono solo
essere associate al thread corrente, oppure esistono altre tecniche
che non conosco ma che tu, d'altra parte, non mi citi :-D
Ce ne sono diverse, ma fino a ieri ti ho semplicemente detto perché quelle
che tu hai citato NON possono essere usate.

Hai buttato il discorso su asp.net che è un caso del tutto particolare ma
se, come ti ho già detto, sposti il discorso in una console app che lavora
in un solo appdomain, allora il discorso teorico funziona (vedi anche i test
che ho postato) perché threadstatic è uno di quei meccanismi che ti permette
di recuperare dei dati contestualmente ad un thread. Ma se esci da questo
caso e vai su asp.net, il discorso è radicalmente differente perché queste
condizioni NON sono più rispettate.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-21 09:16:37 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Facciamo il discorso partendo alla rovescia.
[CUT]
Ciao Raff,
abbandoniamo la teoria a favore di un po' di pratica.

Ho una classe RequestX [aggiungo la X in modo che parlandone si riducano
le ambiguità]. RquestX wrappa Request e facendo operazioni pesanti
vorrei che non riwrappasse ogni volta al volo Request ma lo facesse una
sola volta nel costruttotre e poi restasse a disposizione
dell'applicazione per tutta la vita della pagina.
Ecco la classe, ridotta a una banalità:

namespace TestStatic
{
public enum Language { Italian, English }

public class RequestX
{
private Language mLanguage;

public RequestX()
{
mLanguage = System.Web.HttpContext.Current.Request["l"] ==
"en" ? Language.English : Language.Italian;
}
public Language Language
{
get { return mLanguage; }
}
}
}


Questa classe RequestX potrebbe essere inizializzata nella mia WebPage
ma l'applicazione in discussione usa molte classi che usano a loro volta
RequestX e, anzichè far girare moltissimi riferimenti vorrei che
RequestX fosse statica, come lo è System.Web.HttpContext.Current.Request.
Come fare?
Ecco una soluzione possibile, parto eriditando da Page:

namespace TestStatic
{
public class Page:System.Web.UI.Page
{
[System.ThreadStatic()] private static RequestX mRequestX;
public Page()
{
this.PreInit += new System.EventHandler(Page_PreInit);
}
void Page_PreInit(object sender, System.EventArgs e)
{
mRequestX = new RequestX();
}
public static RequestX RequestX
{
get { return mRequestX; }
}
}
}

A questo punto le mie pagine web erediteranno da TestStatic.Page anzichè
da System.Web.UI.Page [Cosa che in ogni caso io faccio quasi sempre], e
dovrei essere a posto, faccio un test:

public partial class _Default : TestStatic.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(
System.Web.HttpContext.Current.Request["l"] + " " +

System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()+ " "+
TestStatic.Page.RequestX.Language);
}
}


Su firefox http://localhost/website10/?l=en :
Ottengo alternativamente e correttamente "en 5 English" e "en 10 English"

su ie http://localhost/website10/?l=it :
Ottengo alternativamente e correttamente "en 5 Italian" e "en 10 Italian"

Tu affermi che questa tecnica è assurda e sbagliata, perchè? Tu come
faresti?

marc.
Raffaele Rialdi [MVP]
2008-03-21 10:57:43 UTC
Permalink
Post by Marcello
Ciao Raff,
abbandoniamo la teoria a favore di un po' di pratica.
Se poi sotto mi torni a parlare di classi web, la teoria non la puoi
abbandonare ;-)
Post by Marcello
Ho una classe RequestX [aggiungo la X in modo che parlandone si
riducano le ambiguità]. RquestX wrappa Request e facendo operazioni
pesanti vorrei che non riwrappasse ogni volta al volo Request ma lo
facesse una sola volta nel costruttotre e poi restasse a disposizione
dell'applicazione per tutta la vita della pagina.
[...]
Post by Marcello
Questa classe RequestX potrebbe essere inizializzata nella mia WebPage
ma l'applicazione in discussione usa molte classi che usano a loro
volta RequestX e, anzichè far girare moltissimi riferimenti vorrei che
RequestX fosse statica, come lo è
System.Web.HttpContext.Current.Request. Come fare?
[...]
Post by Marcello
Tu affermi che questa tecnica è assurda e sbagliata, perchè? Tu come
faresti?
1. ritengo che sia un approccio sbagliato perché leghi il recupero della tua
unica istanza al thread. Questo implica che qualsiasi operazione asincrona
tu faccia, non può accedere al tuo oggetto.
Esempi:
- pagine asincrone (vedi libro di Dino),
- handler asincroni (forse anche più usati delle pagine asincrone)
- uso di workflow foundation dentro asp.net,
- uso di librerie che facciano uso di thread secondari che debbano accedere
al tuo oggetto

2. La soluzione è molto più semplice, priva di controindicazioni ed è quella
Post by Marcello
Se vuoi condividere per ogni utente usa Session oppure Cache usando come key
il prefisso SessionID + qualcosa.
Il SessionID viene sempre generato ed è univoco per la *tua* richiesta.
- Se il browser ha disabilitato il session cookie (da non confondere con i
cookie che sono tutt'altro), il tuo sessionid è sempre differente (ma esiste
ed è comunque valido per tutto il ciclo di vita della pagina)
- Se il browser ha abilitato il session cookie (come è di default per tutti)
hai in più la possibilità di conservare la tua richiesta anche oltre al
ciclo di vita della singola pagina, ottimizzando così le risorse e le
prestazioni.

In alternativa puoi fare quello che fa Asp.net, cioè quello di usare
ILogicalThreadAffinative e NON ThreadStatic.

Ovviamente se a te stanno bene le limitazioni sei liberissimo di farlo, ma
come ho detto fin dall'inizio, l'uso di var statiche in asp.net per questi
scopi è da evitarsi e le alternative sono più valide.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-21 11:35:02 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Se poi sotto mi torni a parlare di classi web, la teoria non la puoi
abbandonare ;-)
Ok, Raff, abbandono.
Context.Current sarà implementato da qualche parte tramite
ILogicalThreadAffinative che non ha e non può avere alcunissimo rapporto
con i Thread a parte il nome.

marc.
Marcello
2008-03-21 13:00:06 UTC
Permalink
Post by Marcello
Ok, Raff, abbandono.
Ultima cosa Raff,
io ho una blanda formazione da fisico e tendo a ragionare in modo
sicuramente semplicistico e a banalizzare, ma...

Esistono variabili statiche e non statiche e queste non bastano a
spiegare il comportamento di Context.Current. Da pochi giorni ho
scoperto che esiste anche ThreadStatic() e questo può aiutare moltissimo
e anzi, dare una soluzione al problema [parziale, perchè come hai
evidenziato giustamente ci sono dei limiti].
Ora, o ci sono altri modificatori delle variabili o serve a poco, mi
pare, tirare in ballo socket, interfacce e tecniche di alto livello
visto che a baso livello dovranno pur usare variabili o statiche o non
statiche o threadstatic(). O c'è altro? Quindi mi pare che un
ragionamento riduzionista porti a concludere che:

1) static e non static non bastano per spiegare il comportamento di
Context.Current
2) threadstatic() permette di spiegarlo.
3) O esistono altri modificatori [o attributi] o da qualche parte
Context.Current o una classe chiamata da quest'ultima legge una
variabile di tipo ThreadStatic().

Ti sembra un ragionamento illogico?
Post by Marcello
marc.
rimarc.
Raffaele Rialdi [MVP]
2008-03-21 13:52:32 UTC
Permalink
Post by Marcello
Esistono variabili statiche e non statiche e queste non bastano a
spiegare il comportamento di Context.Current. Da pochi giorni ho
scoperto che esiste anche ThreadStatic() e questo può aiutare
moltissimo e anzi, dare una soluzione al problema [parziale, perchè
come hai evidenziato giustamente ci sono dei limiti].
Può aiutare in scenari non asp.net, dove tu hai il pieno controllo del pool
e dove non c'è un runtime che ti può fare gli scherzi.
Post by Marcello
Ora, o ci sono altri modificatori delle variabili o serve a poco, mi
pare, tirare in ballo socket, interfacce e tecniche di alto livello
visto che a baso livello dovranno pur usare variabili o statiche o non
statiche o threadstatic(). O c'è altro? Quindi mi pare che un
1) static e non static non bastano per spiegare il comportamento di
Context.Current
2) threadstatic() permette di spiegarlo.
static+threadstatic non lo spiegano perché HttpContext si comporta
diversamente da una analoga variabile statica marcata con ThreadStatic. In
casi limite (o dal punto di vista piccolo, per un intevallo epsilon piccolo
a piacere) possono anche spiegarlo ma rimangono casi particolari.
Post by Marcello
3) O esistono altri modificatori [o attributi] o da qualche parte
Context.Current o una classe chiamata da quest'ultima legge una
variabile di tipo ThreadStatic().
Il CLR da una parte e Win32 sono il tuo ecosistema. Questo ecosistema ti
mette a disposizione altri meccanismi (gli atom di win32, i context del fx
dall'altra sono un esempio) che ti permettono di associare delle
informazioni e poterle recuperare in modo contestuale.
La logica del contesto è variabile e dipende dalla specifica tecnologia. Nel
caso di asp.net, il contesto in cui è disponibile HttpContext è deciso da
asp.net che fa *uso* del supporto offerto dai Context del fx.

Le attached property di wpf sono statiche eppure recuperano dati privati
usando un dictionary per abbinare il valore della proprietà statica a quella
specifica istanza.

I meccanismi perciò non sono una prerogativa di modificatori, attributi e
linguaggi.
Alla fine quello che vuoi fare è abbinare un valore ad un altro che funge da
"ancora". Che questa ancora sia uno static, il TLS, un atom, o qualsiasi
altra cosa, il risultato è sempre quello. Si tratta solo di scegliere il
meccanismo giusto per evitare i problemi di cui abbiamo ampiamente parlato.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-21 12:23:14 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Ovviamente se a te stanno bene le limitazioni sei liberissimo di farlo,
ma come ho detto fin dall'inizio, l'uso di var statiche in asp.net per
questi scopi è da evitarsi e le alternative sono più valide.
Ciao Raf,
perdona il tono sarcastico ma credo che al prossimo summit a Seattle
sarà il caso di spiegare le limitazioni del metodo anche in ms,
pungolato da Alessandro ho fatto questo test:

private static string x=null;
protected void Page_Load(object sender, EventArgs e)
{
System.Threading.Thread t = new System.Threading.Thread(new
System.Threading.ThreadStart(MetodoThread));
t.Start();
for (; x == null; ) ;
Response.Write("l=" + x);
}
private void MetodoThread()
{
if(System.Web.HttpContext.Current==null){
x="Non esiste il context qui!";
return;
}

x = "Tutto bene";

}


E il responso è "Non esiste il context qui!".
marc.
Raffaele Rialdi [MVP]
2008-03-21 13:34:00 UTC
Permalink
Post by Marcello
Ciao Raf,
perdona il tono sarcastico ma credo che al prossimo summit a Seattle
sarà il caso di spiegare le limitazioni del metodo anche in ms,
[...]

Sei in asp.net e le questioni sono più complesse perché è sempre il runtime
che decide quando il context è valido o meno.
Cioè è lui che decide se usare quella zona dati in cui viene recuperato
HttpContext dalla proprietà statica Context.

Andiamo su un caso reale, una pagina asincrona di asp.net
Crea una nuova page e marcala asincrona:
<%@ Page Async="true" .... %>

Poi nel code behind metti questo codice:

public partial class Async : System.Web.UI.Page
{
private WebRequest _request;

void Page_Load(object sender, EventArgs e)
{
HttpContext ctx = HttpContext.Current;
System.Diagnostics.Trace.WriteLine("Page_Load> Tid = " +
Thread.CurrentThread.ManagedThreadId.ToString() +
" and Ctx is " + ((ctx == null) ? "null" : "valid"));

AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation)
);
}

protected override void Render(HtmlTextWriter writer)
{
HttpContext ctx = HttpContext.Current;
System.Diagnostics.Trace.WriteLine("Render> Tid = " +
Thread.CurrentThread.ManagedThreadId.ToString() +
" and Ctx is " + ((ctx == null) ? "null" : "valid"));

base.Render(writer);
}

IAsyncResult BeginAsyncOperation(object sender, EventArgs e,
AsyncCallback cb, object state)
{
HttpContext ctx = HttpContext.Current;
System.Diagnostics.Trace.WriteLine("BeginAsyncOperation> Tid = " +
Thread.CurrentThread.ManagedThreadId.ToString() +
" and Ctx is " + ((ctx == null) ? "null" : "valid"));

_request = WebRequest.Create("http://www.microsoft.com");
return _request.BeginGetResponse(cb, state);
}

void EndAsyncOperation(IAsyncResult ar)
{
HttpContext ctx = HttpContext.Current;
System.Diagnostics.Trace.WriteLine("EndAsyncOperation> Tid = " +
Thread.CurrentThread.ManagedThreadId.ToString() +
" and Ctx is " + ((ctx == null) ? "null" : "valid"));
}


La pagina è costruita per avere poco codice e non mostrare niente ma
nell'output di Visual Studio troverai:
Page_Load> Tid = 4 and Ctx is valid
BeginAsyncOperation> Tid = 4 and Ctx is valid
EndAsyncOperation> Tid = 8 and Ctx is null
Render> Tid = 8 and Ctx is valid

Cioè HttpContext viene *reso valido* da asp.net in due thread differenti, il
4 e l'8, ma solo quando lui ritiene che sia necessario che tu possa
accederci.

Adesso è più chiaro?
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-21 13:44:17 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Adesso è più chiaro?
Mi spiace Raf, ma è sembra solo più chiaro che quello che diaciamo io e
Alessandro è corretto. Se fai gestire a i thread asincroni a un oggetto
dedicato questo evita i problemi esposti probabilmente appiccicando il
context a qualche variabile threadstatic()

marc.
AlessandroD
2008-03-21 13:55:41 UTC
Permalink
Post by Marcello
Post by Raffaele Rialdi [MVP]
Adesso è più chiaro?
Mi spiace Raf, ma è sembra solo più chiaro che quello che diaciamo io e
Alessandro è corretto. Se fai gestire a i thread asincroni a un oggetto
dedicato questo evita i problemi esposti probabilmente appiccicando il
context a qualche variabile threadstatic()
Qualcuno sa se c'è un modo per lanciare il reflector su un gruppo di dll per
avere indietro il disassemblato di tutto e piazzarlo dentro un il notepad
per dire.
In modo da cercarci dentro sto cristo di attributo threadstatic() e vedere
dove è usato.
Magari così è più facile capire se c'entra qualcosa con la
HttpContext.Current oppure no.
--
Ciao, Alessandro

/*
Alessandro Dereani
Microsoft MVP - SQL Server
http://mvp.support.microsoft.com
*/
AlessandroD
2008-03-21 15:00:35 UTC
Permalink
Post by AlessandroD
In modo da cercarci dentro sto cristo di attributo threadstatic() e vedere
dove è usato.
Chiarisco che il senso di quella frase non vuole essere offensivo,
assolutamente.
L'uso improprio che ho fatto della parola cristo nelle mie intenzioni è alla
pari di "sto cavolo", in riferimento al senso di quella frase.
Un po' come in modo discorsivo si usa l'espressione "oddio .....".
Vista l'ampiezza del thread e i ping pong di confronti occorsi, ho voluto
comunicare il mio stato di "ansia" per cercare una soluzione chiara alla
domanda che ha fatto partire il thread (se HttpContext.Currrent usa o meno
in qualche maniera l'attributo threadstatic()).
Se qualcuno si è sentito infastidito o offeso per la forma che ho usato per
esprimermi chiedo sinceramente scusa.
--
Ciao, Alessandro

/*
Alessandro Dereani
Microsoft MVP - SQL Server
http://mvp.support.microsoft.com
*/
Raffaele Rialdi [MVP]
2008-03-21 13:58:10 UTC
Permalink
Post by Marcello
Mi spiace Raf, ma è sembra solo più chiaro che quello che diaciamo io
e Alessandro è corretto. Se fai gestire a i thread asincroni a un
oggetto dedicato questo evita i problemi esposti probabilmente
appiccicando il context a qualche variabile threadstatic()
Io proprio non ti capisco.
Ti ho mostrato un esempio classico e semplice di una pagina asincrona che
usa due thread.
In quell'esempio:
- HttpContext.Current è valido
- [ThreadStatic] non funzionerebbe.

boh
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-21 14:35:10 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Io proprio non ti capisco.
Ti ho mostrato un esempio classico e semplice di una pagina asincrona
che usa due thread.
- HttpContext.Current è valido
- [ThreadStatic] non funzionerebbe.
...mmm... come fare?
Proviamo proprio a livello super elementare:

Una variabile può essere dichiarata:

Static, Non static, ThreadStatic() esistono altri modificatori per
definitre l'ambito di validità di una variabile?
Post by Raffaele Rialdi [MVP]
boh
marc.
Raffaele Rialdi [MVP]
2008-03-21 16:29:11 UTC
Permalink
Post by Marcello
Post by Raffaele Rialdi [MVP]
- HttpContext.Current è valido
- [ThreadStatic] non funzionerebbe.
...mmm... come fare?
Static, Non static, ThreadStatic() esistono altri modificatori per
definitre l'ambito di validità di una variabile?
modifier nei termini del linguaggio oltre a static sono public, internal,
etc. ma non credo che siano quelli a cui tu alludi.

Ci sono delle api/librerie che ti permettono di associare un reference ad un
contesto. HttpContext usa il ILogicalThreadAffinative, un altro è AppDomain
GetData/SetData, poi c'è Thread GetData/SetData, una serie nelle Win32
(RegisterWindowMessage per dirne un'altro), e probabilmente la lista è
ancora lunga.

Il fatto che threadstatic abbia la "facility" di essere un attributo non gli
attribuisce nessun valore speciale rispetto alle altre api/librerie citate.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-21 17:23:49 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Post by Marcello
Static, Non static, ThreadStatic() esistono altri modificatori per
definitre l'ambito di validità di una variabile?
modifier nei termini del linguaggio oltre a static sono public,
internal, etc. ma non credo che siano quelli a cui tu alludi.
Ci sono delle api/librerie che ti permettono di associare un reference
ad un contesto. HttpContext usa il ILogicalThreadAffinative, un altro è
AppDomain GetData/SetData, poi c'è Thread GetData/SetData, una serie
nelle Win32 (RegisterWindowMessage per dirne un'altro), e probabilmente
la lista è ancora lunga.
Il fatto che threadstatic abbia la "facility" di essere un attributo non
gli attribuisce nessun valore speciale rispetto alle altre api/librerie
citate.
Ok, un po' estesa come risposta ma la prendo per un "No, non ce ne sono
altri". Io da questo deduco che per Scrivere all'interno del clr un
classe che si comporti come System.Web.HttpContext.Current è necessario
usare un attributo threadstatic() tu invece affermi che la deduzione è
sbagliata. Ma di logiche ce ne sono tante e ognuno ha legittimamente
diritto di dedurre quello che crede.
Post by Raffaele Rialdi [MVP]
Ci sono delle api/librerie che ti permettono di associare un reference
ad un contesto. HttpContext usa il ILogicalThreadAffinative, un altro è
AppDomain GetData/SetData, poi c'è Thread GetData/SetData, una serie
nelle Win32 (RegisterWindowMessage per dirne un'altro), e probabilmente
la lista è ancora lunga.
Al loro interno, per essre sviluppate in c# devono contenere variabili o
static o threadstatic o non statiche e quindi non modificano di una
virgola la mia deduzione. L'unico dubbio, appurato che non esistono
modificatori aggiuntivi, è la possibilità di uscire dal clr verso
linguaggi che al contrario offrano modificatori diversi.
Post by Raffaele Rialdi [MVP]
Il fatto che threadstatic abbia la "facility" di essere un attributo non
gli attribuisce nessun valore speciale rispetto alle altre api/librerie
citate.
A mio parere non è una questione di facility, ma, a mio modestissimo
avviso, di logica. Se il processore è a 2 bit significa che accetta
chiamate del tipo 00, 01, 10 o 11 e non importa nulla se esiste un os
per quel processore che gestisce interi enormi, la struttura del
processore permette di dedurre che ad un certo livello si manipolano
solo 4 interi: 0, 1, 2 e 3.

marc.
Marcello
2008-03-21 17:34:24 UTC
Permalink
Post by Marcello
L'unico dubbio, appurato che non esistono
modificatori aggiuntivi, è la possibilità di uscire dal clr verso
linguaggi che al contrario offrano modificatori diversi.
Attenzione che se quanto quotato è vero e se per implementare
System.web.HttpContext.Current non si può usare threadstatic, secondo la
logica a cui faccio riferimento io, se ne deduce che non è possibile
implementare classi che si comportino come
System.web.HttpContext.Current in c# puro.
Post by Marcello
marc.
rimarc.
Raffaele Rialdi [MVP]
2008-03-21 17:47:41 UTC
Permalink
Post by Marcello
Attenzione che se quanto quotato è vero e se per implementare
System.web.HttpContext.Current non si può usare threadstatic, secondo
la logica a cui faccio riferimento io, se ne deduce che non è
possibile implementare classi che si comportino come
System.web.HttpContext.Current in c# puro.
Con il "C" puro non puoi neppure stampare una stringa su stdout ... ci vuole
la libreria stdlib o iostream e senza le CRT non puoi eseguire una new di
C++, etc.
Non esiste il concetto di "puro"
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-21 17:48:16 UTC
Permalink
Post by Marcello
Io da questo deduco che per Scrivere all'interno del clr un
classe che si comporti come System.Web.HttpContext.Current è necessario
usare un attributo threadstatic() tu invece affermi che la deduzione è
sbagliata. Ma di logiche ce ne sono tante e ognuno ha legittimamente
diritto di dedurre quello che crede.
Ancora una cosa. Sempre secondo la mia logica affermare:

1) Non ci sono modificatori oltre a Static, NonStatic e ThreadStatic
2) System.Web.HttpContext.Current non è implemtato via ThreadStatic

Portano alla necessità che almeno una delle seguenti affermazioni sia vera:

1) System.Web.HttpContext.Current non è implementabile in c#
2) System.Web.HttpContext.Current è implementabile utilizzando solo
metodi static e non statici.

La 1 per me è falsa e mi pare di aver mostrato come è possibile
implementare il comportamento di System.Web.HttpContext.Current in c#.
Mentre la 2 mi sembra falsa o almeno non trovo un modo per implementare
System.Web.HttpContext.Current con variabili semplicemente statiche o
non statiche.
Post by Marcello
marc.
rimarc.
Raffaele Rialdi [MVP]
2008-03-21 17:53:12 UTC
Permalink
Post by Marcello
1) Non ci sono modificatori oltre a Static, NonStatic e ThreadStatic
2) System.Web.HttpContext.Current non è implemtato via ThreadStatic
1) System.Web.HttpContext.Current non è implementabile in c#
2) System.Web.HttpContext.Current è implementabile utilizzando solo
metodi static e non statici.
La 1 per me è falsa e mi pare di aver mostrato come è possibile
implementare il comportamento di System.Web.HttpContext.Current in c#.
Mentre la 2 mi sembra falsa o almeno non trovo un modo per
implementare System.Web.HttpContext.Current con variabili
semplicemente statiche o non statiche.
Stai andando in loop :)
ThreadStatic è un modo "differente" per informare il runtime, rispetto ad
una chiamata esplicita ad una api.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Marcello
2008-03-21 18:39:17 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Stai andando in loop :)
ThreadStatic è un modo "differente" per informare il runtime, rispetto
ad una chiamata esplicita ad una api.
Parto da qui ma intendo rispondere a tutti e tre i tuoi post.
Si, c'è un punto in cui il ragionamento gira su se stesso.
La tua affermazione sulla non esistenza del c o del c# o del c++ puro è
verissima e mette in ginocchio le mie argomentazioni.
Io parto dall'assunto logicamente errato che ThreadStatic sia
accettabile e ILogicalThreadAffinative no come se avessero un qualche
valore diverso, ma non sono altro che due parole, una più breve e una
più lunga le quali contengono entrambe la parola "Thread". Inoltro gioco
le mie carte su un livello basso e strettamente logico in cui esistono
solo le tre entità non static, static e thread static che, in realtà,
non esiste.

Eppure mi resta la sensazione che non sia tutto da buttare e che il
piano di memoria su cui si gioca il comportamento di
System.Web.HttpContext.Current sia quello dei thread e che potrei
ottenere [a essere sinceri ho già cominciato ad applicare la mia idea in
un sito] quel comportamento senza rischi e complicazioni sfruttando
l'attributo [ThreadStatic()] e che comunque le tecniche disponibili
girino intorno continuamente e necessariamente al concetto di thread e
di "variabile del thread" ricadendo inevitabilemnte su forme di
isolamento che ora mi viene naturale riassumenre nel concetto di
[ThreadStatic()].

Mah ci devo pensare su un po'. Mi aspetta una vacanza in giappone, ho
ore di terrore del volo per cercare di distrarmi con pensieri di questo
tipo.

marc.

P.S.
Non sono un fisico purtroppo, ma mi sono ridotto, con tutto il rispetto,
a questa cosa infame di schiacciar giù i bottoni di ste macchinette inutili.

rimarc.

P.P.S.
L'assunto principe della relatività è un principo paradossalmente
assoluto "La velocità della luce è la stessa per tutti gli osservatori
in quiete o in moto".

ririmarc
Raffaele Rialdi [MVP]
2008-03-21 19:13:28 UTC
Permalink
Post by Marcello
Eppure mi resta la sensazione che non sia tutto da buttare e che il
piano di memoria su cui si gioca il comportamento di
System.Web.HttpContext.Current sia quello dei thread e che potrei
ottenere [a essere sinceri ho già cominciato ad applicare la mia idea
in un sito] quel comportamento senza rischi e complicazioni sfruttando
l'attributo [ThreadStatic()] e che comunque le tecniche disponibili
girino intorno continuamente e necessariamente al concetto di thread e
di "variabile del thread" ricadendo inevitabilemnte su forme di
isolamento che ora mi viene naturale riassumenre nel concetto di
[ThreadStatic()].
Applicare ThreadStatic in asp.net non solo è applicabile con le limitazioni
già dette ma apre anche un potenziale buco di sicurezza.
La variabile viene associata al thread grazie a ThreadStatic. Poiché il
thread viene preso dal thread pool che asp.net ricicla a favore di qualsiasi
utente, i dati impostati con threadstatic sopravvivono alla request e
possono essere letti da un altro utente.
Quanto questo sia pericoloso dipende ovviamente dai dati e da come vengono
usati, ma per quello che mi riguarda è un motivo in più (se ce ne fosse
ancora bisogno) per non usarlo in asp.net
Post by Marcello
Mah ci devo pensare su un po'. Mi aspetta una vacanza in giappone, ho
ore di terrore del volo per cercare di distrarmi con pensieri di
questo tipo.
Sit back and relax, il volo è meraviglioso ;-)
Post by Marcello
Non sono un fisico purtroppo, ma mi sono ridotto, con tutto il
rispetto, a questa cosa infame di schiacciar giù i bottoni di ste
macchinette
inutili.
non infierire sulle mie meraviglie :)
Post by Marcello
L'assunto principe della relatività è un principo paradossalmente
assoluto "La velocità della luce è la stessa per tutti gli osservatori
in quiete o in moto".
:)
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Raffaele Rialdi [MVP]
2008-03-21 17:44:53 UTC
Permalink
Post by Marcello
Al loro interno, per essre sviluppate in c# devono contenere
variabili o static o threadstatic o non statiche e quindi non
modificano di una virgola la mia deduzione. L'unico dubbio, appurato
che non esistono modificatori aggiuntivi, è la possibilità di uscire
dal clr verso linguaggi che al contrario offrano modificatori diversi.
[...]
Post by Marcello
A mio parere non è una questione di facility, ma, a mio modestissimo
avviso, di logica. Se il processore è a 2 bit significa che accetta
chiamate del tipo 00, 01, 10 o 11 e non importa nulla se esiste un os
per quel processore che gestisce interi enormi, la struttura del
processore permette di dedurre che ad un certo livello si manipolano
solo 4 interi: 0, 1, 2 e 3.
Ne fai una questione di alto/basso livello? Allora scendiamo di livello.
- A livello di clr, threadstatic è solo un modo per dire al clr di associare
uno static al thread.

Ma visto il tuo esempio scendiamo a livello di assembler, va bene.
In termini di assembler il concetto di static è una fandonia. Lo static è
semplicemente una allocazione di memoria che, grazie ad una *facility* dei
linguaggi ad alto livello vedi uguale anche da quell' "orrenda" (come
probabilmente direbbe Torvalds) astrazione dell'istanza di un oggetto.

Visto che sei un fisico, sarai daccordo che tutto è relativo, no?
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Continua a leggere su narkive:
Loading...