What's a thread doing / Erlang-style processes / Message passing

I'm finding myself in dire need of monitoring the Haskell runtime. More precisely, I would like to know what each that I launch is doing at a given point in time. Is there a way to obtain this information now? I would be fine with knowing if a thread is blocking on a foreign call, MVar or something like that. The question is prompted by my current project and the issues I'm facing now. I believe I minimized the amount of garbage that I'm generating by moving to unboxed arrays from lists (thanks dcoutts) but I still have memory utilization issues. I currently have each thread associated with a TChan and I'm going to try to abstract that today by creating a special type of a thread object that is associated with two mailboxes (in and out). When starting this thread you would supply the event loop to read from the inbox and another one to write to the mailbox. I would also add stats to the TChan mailboxes so that I know the number of messages pending in each mailbox and can monitor it. This mirrors my current architecture where I have each poker bot as three threads: #1 reading messages from a socket and posting to #3, #2 reading messages sent by #3 and writing to the socket, #3 reading messages sent by #1, processing them and posting to #2. I suppose I'm trying to implement Erlang-like processes where each process has a mailbox for incoming messages and can send messages to any other process. In Erlang you can also check how many messages are pending to each process, etc. I don't think implementing message passing on top of exceptions is a good idea but please correct me if I'm wrong. In Erlang you are tasked with implementing the message loop yourself and retrieve messages by using a "receive" construct where you can pattern-match on the type of message inside. It seems that custom messages would need to be implemented on top of Dynamic but is there a way to pattern-match on that? I have messages implemented like this now but is there a better abstraction? data Event = Enter | Exit | Quit | Timeout String | Connected | Disconnected | Error String | Cmd Command | Custom Dynamic -- can't pattern-match on this? deriving Show Last but not least, to be able to send messages to any thread I would need to keep those around in some sort of a table. I would need to create records and keep the thread id, the mailbox and possibly some sort of a per-thread string so that threads can update me on their doings. Do you have any suggestions? Thanks, Joel -- http://wagerlabs.com/

Hello Joel, Tuesday, December 06, 2005, 1:27:58 PM, you wrote: JR> #1 reading messages from a socket and posting to #3, JR> #2 reading messages sent by #3 and writing to the socket, JR> #3 reading messages sent by #1, processing them and posting to #2. what you get by dividing this into 3 threads? i think that this have meaning ONLY if you then join all socket reading threads together and use one select to wait on them all JR> data Event JR> = Enter JR> | Exit JR> | Quit JR> | Timeout String JR> | Connected JR> | Disconnected JR> | Error String JR> | Cmd Command JR> | Custom Dynamic -- can't pattern-match on this? JR> deriving Show using "Dynamic" have meaning only if you don't know at compile time what messsages can be sent. is that really the case? JR> Last but not least, to be able to send messages to any thread I would JR> need to keep those around in some sort of a table. I would need to JR> create records and keep the thread id, the mailbox and possibly some JR> sort of a per-thread string so that threads can update me on their JR> doings. imho, you are think in Erlang style, which is ultimately dynamic and run-time oriented. what you really need - is an abstraction "Poker server" which have interface consisting of several functions, which includes ability to create new server, send it a fixed (at compile time) set of messages, and that's all (may be i don't know about something more). plus abstraction "Logger", which have facility "log to me", this facility passed to routine which creates "Poker server" data Logger = Logger {log :: String -> IO () } createLogger = do c <- newChan forkIO $ loggerThread (readChan c) return $ Logger (log = writeChan c} data Server = Server { send :: Event -> IO () , kill :: IO () } createServer logger socket = do c <- newChan t <- forkIO $ serverThread (log logger) socket (readChan c) return $ Server {send = writeChan c, kill = killThread t} main = do l <- createLogger s <- mapM (createServer l) [1..1000] ... -- Best regards, Bulat mailto:bulatz@HotPOP.com

On Dec 6, 2005, at 1:49 PM, Bulat Ziganshin wrote:
JR> #1 reading messages from a socket and posting to #3, JR> #2 reading messages sent by #3 and writing to the socket, JR> #3 reading messages sent by #1, processing them and posting to #2.
what you get by dividing this into 3 threads? i think that this have meaning ONLY if you then join all socket reading threads together and use one select to wait on them all
I get an abstraction of a thread with two STM-based mailboxes. My workhorse threads don't need to care what is done with the messages that they generate and where the ones that they are consuming come from.
JR> | Custom Dynamic -- can't pattern-match on this? JR> deriving Show
using "Dynamic" have meaning only if you don't know at compile time what messsages can be sent. is that really the case?
That is correct. I deliver a "scripting library" and users can create messages of their own.
imho, you are think in Erlang style, which is ultimately dynamic and run-time oriented.
I think in the style most suitable to my task at hand. I have a variable number of poker clients that talk to the server. These all run concurrently so I'm starting threads for them. They can send/receive messages, so I added mailboxes to the threads, etc. Is there anything wrong with this approach? Thanks, Joel -- http://wagerlabs.com/

Hello Joel, Tuesday, December 06, 2005, 5:12:55 PM, you wrote:
using "Dynamic" have meaning only if you don't know at compile time what messsages can be sent. is that really the case?
JR> That is correct. I deliver a "scripting library" and users can create JR> messages of their own. creators of Data.List library also don't know about all your types, but nevertheless you are use all theirs functions ;) if set of messages is defined at compile time, then it's just: data Event a = Quit | .... | User a user of your library defines additional set of messages with data UserEvent = Beer Int | Cola | ... and use smthg like do chan <- newChan sendChan chan (User $ Beer 5) sendChan chan Quit it seems like magic but Haskell will guess what `chan` have type "Chan (Event UserEvent)" here :)
imho, you are think in Erlang style, which is ultimately dynamic and run-time oriented.
JR> I think in the style most suitable to my task at hand. I have a variable JR> number of poker clients that talk to the server. These all run JR> concurrently JR> so I'm starting threads for them. They can send/receive messages, so JR> I added JR> mailboxes to the threads, etc. Is there anything wrong with this JR> approach? hm, may be that you are mixing interfaces and implementation details. for example, poker client in my taste must be a record which supports all operations on this client via its fields, which is just an actions which accepts/returns some values in general, your questions contain too few details about your problems and too much details about solutions you are assume -- Best regards, Bulat mailto:bulatz@HotPOP.com

Assuming I typed events like that I think I would need a typed sink for them as well. I only have one sink for the events and that is my message queue. I expect users to want User X, User Y, User Z within the same module and that's why I used Dynamic. On Dec 6, 2005, at 4:07 PM, Bulat Ziganshin wrote:
creators of Data.List library also don't know about all your types, but nevertheless you are use all theirs functions ;)
if set of messages is defined at compile time, then it's just:
data Event a = Quit | .... | User a

Hello Joel, Tuesday, December 06, 2005, 8:30:32 PM, you wrote: JR> Assuming I typed events like that I think I would need a typed sink JR> for them as well. I only have one sink for the events and that is my JR> message queue. i don't understand you. remember that i'm not native English speaker :) JR> I expect users to want User X, User Y, User Z within JR> the same module and that's why I used Dynamic. if you can define all these datatags (X, Y and Z) in one type then you can use pattern matching: data UserEvent = X ... | Y ... | Z ... if not - then can't. of course, you can use this "subtyping trick" several times, but it is not very interesting: data Event a = ... | User a data UserEvent1 a = X ... | User2 a data UserEvent2 a = Y ... | User3 a send chan (User $ User2 $ Y) -- type of expression inside brackets is "Event (UserEvent1 (UserEvent2 a))", where a is unspecified or you can define data Event a b c = ... | User1 a | User2 b | User3 c but this is also bad :( you can also use classes, but Dynamic actually does the same, and this gives you no ability to do pattern-matching -- Best regards, Bulat mailto:bulatz@HotPOP.com
participants (2)
-
Bulat Ziganshin
-
Joel Reymont