As was foretold, we've added advertisements to the forums! If you have questions, or if you encounter any bugs, please visit this thread: https://forums.penny-arcade.com/discussion/240191/forum-advertisement-faq-and-reports-thread/
Options

SELECT * FROM posts WHERE tid = 'PA PROGRAMMING THREAD'

16869717374100

Posts

  • Options
    an_altan_alt Registered User regular
    FYI, some new CS courses (amongst others) are up at http://coursera.org/.

    Pony wrote:
    I think that the internet has been for years on the path to creating what is essentially an electronic Necronomicon: A collection of blasphemous unrealities so perverse that to even glimpse at its contents, if but for a moment, is to irrevocably forfeit a portion of your sanity.
    Xbox - PearlBlueS0ul, Steam
    If you ever need to talk to someone, feel free to message me. Yes, that includes you.
  • Options
    CantidoCantido Registered User regular
    edited April 2012
    Saeris wrote: »
    Python seems like it'd be a great introductory language. It has that robust, clean syntax with very helpful error messages that new students really benefit from.

    Lua has this as well, but you sort of have to roll your own object-oriented framework. Not that it's difficult; it only requires about 10 lines to define a nice base Object prototype. But that's one more barrier to entry. Python has that support built right into the language.

    Either way, I'm glad I started with a language that has closures and first-class functions. Those concepts are way too important and useful to be left until later. My university, for instance, taught the entire curriculum in Java and C/C++; most of my graduating class never wrote a single closure. Even the idea behind Java's anonymous classes was barely covered.

    Some shenanigans with my degree audit really screwed me over. Learning Intro to C was how all CS and CompEngineers start out, then they move on to CS1. This part is fine. The CS1 course used C to teach data structures and binary trees. What messed me up was that my degree audit was old, so I ended up taking OOP (java) and CS2 (which assumed you already took Java) simultaneously. Trying to do the coursework was a nightmare but the tests were easy.

    Cantido on
    3DS Friendcode 5413-1311-3767
  • Options
    Monkey Ball WarriorMonkey Ball Warrior A collection of mediocre hats Seattle, WARegistered User regular
    I would say that the only problem with Python as a intro to coding language is its unorthodox scoping/code block syntax, i.e. significant white space vs. the almost universal C syntax with curly braces. But that part of python still rubs me the wrong way, even though I otherwise really like it. So this might just be a personal qualm.

    "I resent the entire notion of a body as an ante and then raise you a generalized dissatisfaction with physicality itself" -- Tycho
  • Options
    SaerisSaeris Borb Enthusiast flapflapflapflapRegistered User regular
    That part of Python has never bothered me, because that's almost exactly how I indent and format code in other languages anyway.

    borb_sig.png
  • Options
    KambingKambing Registered User regular
    The primary problems with Python at the intro level are the lack of static typing and the fact that it is sometimes difficult to talk about abstraction in design as a result. The good thing is that in a traditional CS1 course you tend to write small programs and emphasize other fundamentals over abstraction, so the problems end up being mitigated by design.

    @TwitchTV, @Youtube: master-level zerg ladder/customs, commentary, and random miscellany.
  • Options
    Mike DangerMike Danger "Diane..." a place both wonderful and strangeRegistered User regular
    So, right now in my database I have a Majors table and a Requirements table. The Majors table is mostly for prettyprinting/rendering stuff; the Requirements table has got my scheme for representing degree requirements.

    Now, I had been doing stuff through the Majors/Requirements controller, but it seems like those aren't a good fit for what I'm thinking about here:

    User goes to site -> User picks major from list -> User selects completed courses -> User sees courses remaining + suggestions for next semester

    Before I go zooming off into the distance, my thinking right now is that I should be using the Sessions controller.

    User goes to site -> new session
    User picks major from list -> result stored in session
    User picks completed courses -> results stored in session
    Logic performed on selections, results displayed.

    Is this right? It just seems like defining actions on the Requirement/Majors controller doesn't seem right (as those would be if I was creating a new/updating an old instance of those).

    Also, is there an IRC room for this thread? I feel like I have been clogging things up with dumb ol' Rails questions.

    Steam: Mike Danger | PSN/NNID: remadeking | 3DS: 2079-9204-4075
    oE0mva1.jpg
  • Options
    admanbadmanb unionize your workplace Seattle, WARegistered User regular
    edited April 2012
    "Dumb" questions are pretty much 90% of what this thread is for.

    When a User picks a major is that supposed to be an action that permanently (barring a later remove action) associates that user with that major? If so, you should have a database association between users and majors. A Sessions controller is a good thing to have, but you shouldn't be using it to handle actions involving majors or courses (I'm not 100% sure that's what you were suggesting, but it seemed like it). The Sessions controller should exclusively handle creating/updating/deleting sessions -- i.e. signin/signout.

    It sounds to me like what you want is to have a many-to-many relationship between majors and requirements, then you add the embedded resource to your router. Then if your user picked the major with id 3, the route would look like this:

    /majors/3/reqs/index

    with an edit action for a req with id 5 looking like

    /majors/3/reqs/5/edit

    for example.

    admanb on
  • Options
    SyphyreSyphyre A Dangerous Pastime Registered User regular
    After my schooling and after learning a few more languages, I think my choice, for a new programmer, would be to learn both Python and C, in no particular order. That will give you a basis for 95% of what you encounter in the real world.

  • Options
    jackaljackal Fuck Yes. That is an orderly anal warehouse. Registered User regular
    7095238893_5000f6e57d.jpg

  • Options
    bowenbowen How you doin'? Registered User regular
    jackal wrote: »
    7095238893_5000f6e57d.jpg

    Hm that would probably work okay as a hammer using the top part of the curve.

    Maybe you meant this kind of hammer:

    9Uz6GCsIahrtL1zyNPUTwA3UHWd_CkRnQ5eKvg3MjvDm2cxqgOu2iodV692NEEZWoaGLYlUKMgPMIvPY9b2zBHqScxo80ZA5dNJLzS1gu693kP3qyPUTuzwhKcI8HLjO2vLwHm3R_JPPWQvs_g

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    SyphyreSyphyre A Dangerous Pastime Registered User regular
    Ok that was amusing having read that php article.

  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    Okay I thought if you used "synchronized" on a method that means two threads can't go into it at the same time. Am I right or wrong?

    Here's the code I'm using:
    public class ThreadingExample extends Thread{
        
        private int count = 0;
        
        public ThreadingExample(String s){
            super(s);
        }
        
        public synchronized void output(){
            
            try{
                
                System.out.println(getName() + " count: " + count);
                count++;
                sleep(3000);
            } catch (InterruptedException e){}
            
        }
        
        public void run() {
            
            for(int i = 0; i < 10; ++i){
                
                output();
                try {
                    sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {}
            }
            System.out.println("Complete: " + getName());
        }
    }
    
    public class MultiThreadTest {
        
        public static void main(String[] args) {
            
            new ThreadingExample("Duck Season!").start();
            try {
                
                Thread.sleep(1000);
            } catch (InterruptedException ex) {          
            }
            new ThreadingExample("Wabbit Season!").start();
        }
    }
    

  • Options
    bowenbowen How you doin'? Registered User regular
    Yeah it should be blocking the rest afaik.

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    I thought so too but it seems to go in the method at the same time.

  • Options
    bowenbowen How you doin'? Registered User regular
    edited April 2012
    Try moving your sleeps to before your output. I'm wondering if because the sleeps are at the end of the function if it just lets them pass.

    Also I'm wondering if because you're not accessing any variables, the JRE assumes that it's safe to let them both enter at the same time. Edit: nevermind I see the output++ there now.

    bowen on
    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    Output when I switched count to a static variable. Seemed to work except at the end?
    Duck Season! count: 1
    Wabbit Season! count: 2
    Duck Season! count: 3
    Wabbit Season! count: 4
    Duck Season! count: 5
    Wabbit Season! count: 6
    Duck Season! count: 7
    Wabbit Season! count: 8
    Duck Season! count: 9
    Wabbit Season! count: 10
    Duck Season! count: 11
    Wabbit Season! count: 12
    Duck Season! count: 13
    Wabbit Season! count: 14
    Duck Season! count: 15
    Wabbit Season! count: 16
    Duck Season! count: 17
    Wabbit Season! count: 18
    Wabbit Season! count: 19
    Duck Season! count: 20
    Complete: Wabbit Season!
    Complete: Duck Season!

  • Options
    jackaljackal Fuck Yes. That is an orderly anal warehouse. Registered User regular
    I see your bug. The last "Duck Season!" should be "Duck Season! FIRE!"

  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    jackal wrote: »
    I see your bug. The last "Duck Season!" should be "Duck Season! FIRE!"

    :^: :^:

  • Options
    bowenbowen How you doin'? Registered User regular
    I don't see what's wrong with your examples there. Your random sleep will cause them to be in random orders, obviously?

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    seabassseabass Doctor MassachusettsRegistered User regular
    urahonky wrote: »
    Output when I switched count to a static variable. Seemed to work except at the end?
    Duck Season! count: 1
    Wabbit Season! count: 2
    Duck Season! count: 3
    Wabbit Season! count: 4
    Duck Season! count: 5
    Wabbit Season! count: 6
    Duck Season! count: 7
    Wabbit Season! count: 8
    Duck Season! count: 9
    Wabbit Season! count: 10
    Duck Season! count: 11
    Wabbit Season! count: 12
    Duck Season! count: 13
    Wabbit Season! count: 14
    Duck Season! count: 15
    Wabbit Season! count: 16
    Duck Season! count: 17
    Wabbit Season! count: 18
    Wabbit Season! count: 19
    Duck Season! count: 20
    Complete: Wabbit Season!
    Complete: Duck Season!

    You warm the cockles of my heart Uratonky. If it breaks once, with concurrency, it's likely that it will break consistently.

    Also, the output doesn't look wrong to me. You've got a semaphore on output only, meaning you can't have concurrent output. Since the sleeps are random, I think one thread can go twice before the other, no?

    Run you pigeons, it's Robert Frost!
  • Options
    bowenbowen How you doin'? Registered User regular
    Yeah his random sleep time could cause one to fire 3 times before the other.

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    Okay yeah you guys are right. I changed that but now I'm getting something even more confusing... Does this mean the threads are entering the method at the exact same time?
    Duck Season! count: 1
    Wabbit Season! count: 1
    Wabbit Season! count: 3
    Duck Season! count: 3
    Duck Season! count: 5
    Wabbit Season! count: 5
    Duck Season! count: 7
    Wabbit Season! count: 7
    Duck Season! count: 9
    Wabbit Season! count: 9
    Duck Season! count: 11
    Wabbit Season! count: 11
    Duck Season! count: 13
    Wabbit Season! count: 13
    Wabbit Season! count: 15
    Duck Season! count: 15
    Wabbit Season! count: 17
    Duck Season! count: 17
    Wabbit Season! count: 19
    Duck Season! count: 19
    Complete: Duck Season!
    Complete: Wabbit Season!

  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    I'm sorry. I'm reading through the Oracle Java Certification Study Guide and trying out the example they have in the book, then just tweaking it a bit to try out various outputs.

  • Options
    seabassseabass Doctor MassachusettsRegistered User regular
    urahonky wrote: »
    I'm sorry. I'm reading through the Oracle Java Certification Study Guide and trying out the example they have in the book, then just tweaking it a bit to try out various outputs.

    Is the example actually Duck/Wabbit season? Because that would be awesome.

    Run you pigeons, it's Robert Frost!
  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    seabass wrote: »
    urahonky wrote: »
    I'm sorry. I'm reading through the Oracle Java Certification Study Guide and trying out the example they have in the book, then just tweaking it a bit to try out various outputs.

    Is the example actually Duck/Wabbit season? Because that would be awesome.

    Nah that was me. :P I figured that since it'll be repeating it's better than Jamaica and Fiji.

  • Options
    bowenbowen How you doin'? Registered User regular
    Basically how I think synchronized works is they are in the same method at the same time, but, access to variables is a "block" mode. So when they both read the variable it was 3, then they both went to increment it. Oops looks like the first thread is incrementing, have to wait. Looks like they're done, now it's my turn. Doing it.

    http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
    Or use a semaphore of some variety. I find locks to be simple so long as you rule out race conditions preventing your app from working.

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    KambingKambing Registered User regular
    edited April 2012
    Synchronized on a method declaration causes the lock associated with the particular method the object is invoked on to be acquired before executing the method. Static synchronized methods grab the lock associated with the entire class.

    http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.3.6

    In your particular example (the original version), each ThreadingExample instance grabs its own particular lock, so there is no blocking that occurs. And also note that the counter is not shared between the threads because it is non-static which probably defeats the purpose of the exercise. What would work is making the instance variable a static variable instead and then using a synchronized block:
    synchronized(count) {
      // ...
    }
    

    Rather than a method-level synchronized annotation.

    Kambing on
    @TwitchTV, @Youtube: master-level zerg ladder/customs, commentary, and random miscellany.
  • Options
    PhyphorPhyphor Building Planet Busters Tasting FruitRegistered User regular
    edited April 2012
    Synchronized is per-object, not global IIRC. You have two threads synchronizing on their own objects

    Phyphor on
  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    Can't synchronize count since it's not a reference or final (which also defeats the purpose of synchronizing it)

  • Options
    JasconiusJasconius sword criminal mad onlineRegistered User regular
    edited April 2012
    that hammer picture for PHP is inaccurate

    PHP is a balsa wood paint stick and an unpolished sandstone held separately in each hand

    Jasconius on
  • Options
    centraldogmacentraldogma Registered User regular
    So, synchronization on a method only works if the new thread is spawned within the same object? Unless you make the method static?

    When people unite together, they become stronger than the sum of their parts.
    Don't assume bad intentions over neglect and misunderstanding.
  • Options
    bowenbowen How you doin'? Registered User regular
    Ah that makes more sense.

    Why would you need to synchronize two objects accessing their own internal variables?

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    urahonkyurahonky Resident FF7R hater Registered User regular
    Thanks guys. I created a new object, and did this:
    public class ThreadingExample extends Thread {
    
        private static int count = 1;
        private static Integer countInt = 1;
        private ThreadExampleObject obj;
    
        public ThreadingExample(String s, ThreadExampleObject obj) {
            super(s);
            this.obj = obj;
        }
    
        public synchronized void output() {
    
            System.out.println(getName() + " has entered output()...");
            synchronized(obj){
                
                System.out.println(getName() + " is holding the obj for 4000ms...");
                try{
                    
                    Thread.sleep(4000);
                } catch (InterruptedException e){}
                
                obj.setBankAccount(obj.getBankAccount()-10.0);
                System.out.println("money: $" + obj.getBankAccount());
                System.out.println(getName() + " has released the object...");
            }
        }
    
        public void run() {
    
            for (int i = 0; i < 100; ++i) {
    
                output();
            }
            System.out.println("Complete: " + getName());
        }
    }
    

    And it seems to give me a better idea of how synchronization works.

  • Options
    Joe KJoe K Registered User regular
    I would say that the only problem with Python as a intro to coding language is its unorthodox scoping/code block syntax, i.e. significant white space vs. the almost universal C syntax with curly braces. But that part of python still rubs me the wrong way, even though I otherwise really like it. So this might just be a personal qualm.

    Python has a clearly defined blocking structure, its a colon (:) followed by a change in indentation, the block is marked by a change to previous indentation.

    It's not that "whitespace is meaningful", or that there are no delimiters, its that the delimiters are differently defined. They're purposefully chosen this way to make the code more readable, as code is read much more often that it's written.
    an_alt wrote: »
    Java isn't terrible for an into class. It can be tricky to install and configure for Windows users and it's far too verbose for trivial tasks. That being said, the foundations of the language (assignments, comparisons, loops, functions, etc) are logical enough to follow. The "just ignore 90% of the code in the 'Hello World' example- I'll tell you about it later" is unfortunate.

    no, its exactly those things that make it a bad intro language.

    "here, install this ubuntu CD... ok, open a console, type "python" type "print 'hello world'" is far simpler to understand.
    Kambing wrote: »
    Joe K wrote: »
    Kambing wrote: »
    Joe K wrote: »
    Kambing wrote: »

    It would be Racket, technically. =)

    No, python is my choice. The class is a stipped-down version of my traditional intro course I taught last Fall except geared towards high school students and compressed into a 3-4 week chunk instead of 13 (it is for a Summer academy program that offers selected high school students a chance to try out college-caliber courses in technology). With those parameters, Python makes the most sense because it has little cruft when dealing with programming fundamentals and the language transfers well to whatever the student does next (programs on their own, goes to college and takes an actual undergraduate intro cs class).

    At the introductory level, both imperative and functional styles ought to be taught because they require distinct reasoning skills (invariants vs. abstraction) that a computer scientist needs to be able to exhibit. Currently, the majority of the field teaches almost exclusively the former but the tides are slowly changing both at the grassroots level (e.g., see CMU's principles of imperative and principles of functional programming courses) and at the policy level (e.g., see the Computer Science Curricula task force 2013 report).

    It's funny, MIT's Intro to CS Serious course is still done in LISP i think.

    It is nice that functional thinking has come to the forefront recently, personally, i think that it's due to JQuery of all things, but syntacitical sugar for anoymous functions in python, c#, scala and others exposed a lot of people to the style. it's a good thing, because shifting away from this obsessive compulsive disorder about OOP is way overdue.

    MIT has moved from scheme to Python, actually. Northeastern still does everything in Racket. Here at Penn, we've moved from Java to Java+OCaml. Elsewhere people are considering transitions from Java to Python as well, but I think there's a lot of programs holding their breath for the final word from the Curricula task force before they start overhauling.

    i guess the question is python 2.x or 3.x ... there's a forking going on :-)

    Java is awful for a foundation class. At least with C you forced people to work close to the metal. With Python, you get away from template coding, and hide some of the uglier features of C and C++... Honestly, it seems like a clear choice for intro classes.

    For most definitions of an intro class, the concepts that you are teaching don't require you to be anywhere near the metal. So what drives what programming language you use in the class comes from external factors as well as internal (e.g., expectations of other departments and courses downstream within the major).

    yeh, looking back on it, being close to the metal isnt nearly as needed as was 20 years ago :-)

  • Options
    KambingKambing Registered User regular
    Ah yes, forgot about the primitive restriction on sync blocks. You're right. Creating a new object that houses the shared value is the right thing to do. You can also remove synchronized on ThreadingExample.output. And alternatively, you can push the synchronized block onto the methods of your ThreadingExample which makes things slightly more fine-grained although then you get potential interleavings within the debug printlns of output.
    So, synchronization on a method only works if the new thread is spawned within the same object? Unless you make the method static?

    Think of it as protecting resources that are shared across multiple threads. The effect of synchronized is to say that "no one else can access this resource until I am done with it". Then the question becomes what resource you are protecting when you use synchronized. When you synchronize a method, you are protecting the object that the method is invoked on or the class object if the method is static. Whether this is what you need depends on your particular situation (although in practice, it tends to be too coarse-grained for what you need).

    @TwitchTV, @Youtube: master-level zerg ladder/customs, commentary, and random miscellany.
  • Options
    centraldogmacentraldogma Registered User regular
    Is there another way to do concurrency in Java, without extending Thread? I vaguely recall that.

    When people unite together, they become stronger than the sum of their parts.
    Don't assume bad intentions over neglect and misunderstanding.
  • Options
    bowenbowen How you doin'? Registered User regular
    I did something like that before dogma. I'll see if I can't scrap up the code.

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    bowenbowen How you doin'? Registered User regular
    package netLib;
    
    import java.io.*;
    import java.net.*;
    import java.util.*;
    import java.util.concurrent.*;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class Peer extends Thread {
    	private ServerSocket peerServerSocket;
    	private Socket peerClientSocket;
    	
    	private PeerConfiguration configuration;
    	private Hashtable<String,ClientSocket> peerList;
    	
    	private boolean isListening = false;
    	private boolean isConnected = false;
    	private boolean isServer = false;
    	private boolean isAccepting = false;
    	
    	//don't know if these are used currently
    	private PriorityBlockingQueue<Byte[]> outgoingData;
    	private Lock outputLock;
    	private Thread acceptThread;
    	private Thread activityThread;
    	private Object activityLock;
    	
    	private LinkedList<String> uuidsToRemove;
    	
    	public Peer(PeerConfiguration Config) {
    		configuration = Config;
    		
    		//set if we should be using client or server sockets
    		isServer = Config.IsServer();
    		
    		listenerList = new LinkedList<PeerEventListener>();
    		peerList = new Hashtable<String,ClientSocket>();
    		
    		outgoingData = new PriorityBlockingQueue<Byte[]>();
    		//locker for data
    		outputLock = new ReentrantLock();
    		activityLock = new Object();
    		uuidsToRemove = new LinkedList<String>();
    	}
    	
    	public boolean IsActive()
    	{
    		return (isListening || isConnected);
    	}
    	
    	public boolean IsBound()
    	{
    		return isListening;
    	}
    	
    	public boolean IsConnected()
    	{
    		return isConnected;
    	}
    	
    	public String PeerGuid()
    	{
    		if(isServer)
    		{
    			String addr = String.format("%s:%s",
    					peerServerSocket.getInetAddress().getHostAddress(),
    					peerServerSocket.getLocalPort());
    			return NetUuid.GetUuid(addr);
    		}
    		else
    		{
    			String addr = String.format("%s:%s",
    					peerClientSocket.getInetAddress().getHostAddress(),
    					peerClientSocket.getPort());
    			return NetUuid.GetUuid(addr);
    		}
    	}
    	
    	public void Bind()
    	{
    		//make sure we're in server mode, 
    		//and our object isn't already listening (multiple calls prevented)
    		if(isServer)
    		{
    			if(peerServerSocket == null)
    			{
    				try {
    					peerServerSocket = new ServerSocket();
    					if(!peerServerSocket.isBound())
    					{
    						//bind the server
    						peerServerSocket.bind(
    								new InetSocketAddress(configuration.getPort()));
    						
    						//add a listening thread						
    						isListening = true;
    						//this thread will accept connections
    						acceptThread = new Thread(this);
    						activityThread = new Thread(this);
    						acceptThread.start();
    						
    						synchronized(activityLock)
    						{
    							try {
    								activityLock.wait();
    								activityThread.start();
    								System.out.println("Activity Checking...");
    							} catch (InterruptedException e) {
    								// TODO Auto-generated catch block
    								e.printStackTrace();
    							}
    							
    						}
    						
    					}
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    		
    	public void Connect()
    	{
    		if(!isServer)
    		{
    			if(peerClientSocket == null)
    			{
    				try{
    					peerClientSocket = new Socket();
    					//connect to the server
    					peerClientSocket.connect(
    							new InetSocketAddress(configuration.getHost(),
    									configuration.getPort()));
    					
    					//let the client know they're connected
    					raiseEvent(new PeerEvent(this,Constants.PeerEvents.Connected,
    							new PeerEventArgs(null,this)));
    					
    					//add a listening thread
    					isConnected = true;
    					new Thread(this).start();
    					
    				} catch(IOException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    	
    	public void SendData(byte[] Data)
    	{
    		outputLock.lock();
    		Byte[] newData = addTerminatingByte(toObject(Data));
    		//outgoingData.add(newData);
    		synchronized(outgoingData) {
    			outgoingData.offer(newData);
    		}
    		outputLock.unlock();
    	}
    	
    	public void SendData(byte[] Data,RemotePeer ToPeer)
    	{
    		try {
    			OutputStream out = ToPeer.PeerSocket().getOutputStream();
    			byte[] data = Data;
    			out.write(data, 0, Data.length);
    			out.flush();
    		} catch (Exception e) {
    			//send them to be removed
    			raiseEvent(new PeerEvent(this,Constants.PeerEvents.PeerDisconnected,
    					new PeerEventArgs(ToPeer,this)));
    			synchronized(uuidsToRemove) {
    				uuidsToRemove.addLast(ToPeer.PeerUuid());
    			}
    		}		
    	}
    	
    	public void Disconnect()
    	{
    		if(!isServer) {
    			if(peerClientSocket.isConnected()) {
    				isConnected = false;
    				raiseEvent(new PeerEvent(this,Constants.PeerEvents.Disconnected,
    						new PeerEventArgs(null,this)));
    				try {
    					peerClientSocket.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    	
    	public void Unbind()
    	{
    		if(isServer) {
    			isListening = false;
    			//stop the listening thread
    			acceptThread.interrupt();
    			//close all the sockets
    			for(ClientSocket sockObj : peerList.values())
    			{
    				try {
    					sockObj.TheSocket().close();
    				} catch (IOException e) {
    					//don't really care, we're closing the server
    				}
    			}
    			
    			try {
    				peerServerSocket.close();
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	private Byte[] toObject(byte[] Val)
    	{
    		Byte[] retVal = new Byte[Val.length];
    		for(int i = 0; i < Val.length;i++)
    		{
    			retVal[i] = Val[i];
    		}
    		
    		return retVal;
    	}
    	
    	private byte[] toPrimitive(Byte[] Val)
    	{
    		byte[] retVal = new byte[Val.length];
    		for(int i = 0; i < Val.length; i++)
    		{
    			retVal[i] = Val[i].byteValue();
    		}
    		
    		return retVal;
    	}
    	
    	private Byte[] addTerminatingByte(Byte[] Val)
    	{
    		Val = (Byte[])resizeArray(Val,Val.length+1);
    		Val[Val.length-1] = Constants.EOS;
    		return Val;
    	}
    	
    	//this replaces the socketThread from C# code
    	public void run()
    	{
    		int bytesAvailable = 0;
    		byte[] buff;
    		
    		//make sure we're connected or listening
    		while(isConnected || isListening)
    		{
    			//if we're a server, check for incoming
    			//make sure we're not already accepting
    			
    			if(isServer && !isAccepting)
    			{
    				//first thread will start accepting
    				System.out.println("Accepting...");
    				
    				synchronized(activityLock)
    				{
    					activityLock.notify();
    					isAccepting = true;
    				}
    				
    				Socket clntSock;
    				RemotePeer remPeer;
    				
    				while(isListening)
    				{
    					isAccepting = true;
    					//let the activity thread know we'r ready
    					try {
    						//accept a socket
    						//check if there's any accepts
    						
    						clntSock = peerServerSocket.accept();
    						remPeer = new RemotePeer(clntSock);
    						synchronized(peerList) {
    							peerList.put(remPeer.PeerUuid(), new ClientSocket(remPeer));
    						}
    						
    						raiseEvent(new PeerEvent(this,Constants.PeerEvents.PeerConnected,
    								new PeerEventArgs(remPeer,this)));
    						
    					} catch(Exception ex) {
    						//something happened
    						//not really important to the functionality of the program
    					}
    				}
    			}
    						
    			//go through each socket object
    			synchronized(peerList)
    			{
    				for(ClientSocket sockObj : peerList.values())
    				{
    									
    					//get an input stream
    					try {
    					
    						//check how many bytes we can read
    						bytesAvailable = sockObj.In().available();
    						
    						//read those bytes
    						buff = new byte[bytesAvailable];					
    						sockObj.In().read(buff, 0, bytesAvailable);
    						
    						if(bytesAvailable == 0)
    						{
    							//queue a 0x00 byte to be sent to the client
    	
    							this.SendData(new byte[] {0x00},sockObj.ThePeer());
    							
    						}
    						else
    						{
    							for(byte b : buff)
    							{
    								if(b == Constants.EOS)
    								{
    									if(sockObj.BufferByte(b))
    									{
    										Constants.MessageType type = sockObj.FinalizeBuffer();
    										byte[] data = toPrimitive(sockObj.GetData());
    										if(type == null)
    										{
    											//malformed data, drop the client
    											raiseEvent(new PeerEvent(this,Constants.PeerEvents.PeerDisconnected,
    													new PeerEventArgs(sockObj.ThePeer(),this)));
    											synchronized(uuidsToRemove) {
    												uuidsToRemove.addLast(sockObj.ThePeer().PeerUuid());
    											}
    										} 
    										else 
    										{
    										raiseEvent(new PeerEvent(this,Constants.PeerEvents.DataReceived,
    												new PeerEventArgs(sockObj.ThePeer(),this,data,type)));
    										}
    									}
    									else
    									{
    										raiseEvent(new PeerEvent(this,Constants.PeerEvents.PeerDisconnected,
    												new PeerEventArgs(sockObj.ThePeer(),this)));
    										synchronized(uuidsToRemove) {
    											uuidsToRemove.addLast(sockObj.ThePeer().PeerUuid());
    										}
    									}
    								}
    								else
    								{
    									if(!sockObj.BufferByte(b))
    									{
    										raiseEvent(new PeerEvent(this,Constants.PeerEvents.PeerDisconnected,
    												new PeerEventArgs(sockObj.ThePeer(),this)));
    										synchronized(uuidsToRemove) {
    											uuidsToRemove.addLast(sockObj.ThePeer().PeerUuid());
    										}
    										continue;
    									}
    								}
    							}
    						}
    						
    						//zero out the buffer
    						bytesAvailable = 0;
    						buff = null;
    						
    					} catch (Exception e) {
    						// TODO Auto-generated catch block
    						//check to see if we got a disconnect
    						if(e.getMessage() == "Connection reset" ||
    								e.getMessage() == "Socket is closed")
    						{
    							raiseEvent(new PeerEvent(this,Constants.PeerEvents.PeerDisconnected,
    									new PeerEventArgs(sockObj.ThePeer(),this)));
    							synchronized(uuidsToRemove) {
    								uuidsToRemove.addLast(sockObj.ThePeer().PeerUuid());
    							}
    							continue;					
    						}else {
    							//something else happened
    							//e.printStackTrace();
    						}
    					}
    				}
    			}
    			
    			//write what's in the buffers
    			outputLock.lock();
    			if(!outgoingData.isEmpty())
    			{
    				byte[] output = null;
    				try
    				{
    					synchronized(outgoingData) {
    						Byte[] data = outgoingData.take();
    						output = toPrimitive(data);
    					}
    				} catch(Exception ex) {
    					System.out.println("Size " + outgoingData.size());
    					ex.printStackTrace();
    				}
    				if(output != null)
    				{
    					for(ClientSocket sockObj : peerList.values())
    					{
    						try {
    							//System.out.println("Writing " + output.length);
    							sockObj.Out().write(output, 0, output.length);
    							sockObj.Out().flush();
    						} catch (IOException e) {
    							// TODO Auto-generated catch block
    							//e.printStackTrace();
    							raiseEvent(new PeerEvent(this,Constants.PeerEvents.PeerDisconnected,
    									new PeerEventArgs(sockObj.ThePeer(),this)));
    							synchronized(uuidsToRemove) {
    								uuidsToRemove.addLast(sockObj.ThePeer().PeerUuid());
    							}
    							continue;
    						}
    						
    					}
    				}
    			}
    			outputLock.unlock();
    			
    			//remove the bad uuids
    			synchronized(uuidsToRemove) {
    				for(String cliUuid : uuidsToRemove)
    				{
    					
    					try {
    						peerList.get(cliUuid).TheSocket().close();
    					} catch (IOException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    					synchronized(peerList) {
    						peerList.remove(cliUuid);	
    					}
    				}
    			}
    			
    			synchronized(uuidsToRemove)
    			{
    				uuidsToRemove.clear();
    			}
    			
    			try {
    				Thread.sleep(50);
    				Runtime.getRuntime().gc();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				//e.printStackTrace();
    			}
    		}
    		
    	}
    	
    	protected LinkedList<PeerEventListener> listenerList;
    	
    	public void AddEventListener(PeerEventListener listener) {
    		listenerList.add(listener);
    	}
    	
    	public void RemoveEventListener(PeerEventListener listener) {
    		listenerList.remove(listener);
    	}
    	
    	private void raiseEvent(PeerEvent evt){
    		for(int i = 0; i< listenerList.size();i++){
    			listenerList.get(i).eventOccured(evt);
    		}
    	}
    	
    	@SuppressWarnings("rawtypes")
    	private Object resizeArray (Object oldArray, int newSize) {
    		   int oldSize = java.lang.reflect.Array.getLength(oldArray);
    		   Class elementType = oldArray.getClass().getComponentType();
    		   Object newArray = java.lang.reflect.Array.newInstance(
    		         elementType,newSize);
    		   int preserveLength = Math.min(oldSize,newSize);
    		   if (preserveLength > 0)
    		      System.arraycopy (oldArray,0,newArray,0,preserveLength);
    		   return newArray; }
    	
    }
    

    I really don't know what I was thinking with thise code tbh, Java is so wtf compared to my equivalent code in C++ or C#.

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    bowenbowen How you doin'? Registered User regular
    Also fear my column length.

    not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
  • Options
    KambingKambing Registered User regular
    Is there another way to do concurrency in Java, without extending Thread? I vaguely recall that.

    Not sure what you mean by that. Threads are a fundamental concept in traditional concurrency. You can't really "not" deal with them in the sense that they are how you achieve concurrent computation.

    If you're instead talking about synchronized/locks (which is what causes headaches when dealing with shared-memory concurrency) then as Bowen described above, java.util.concurrent provides a variety of lock-free data structures, futures, and atomic variables for you to use.

    If you really mean alternatives to threads, then you are really talking about different models of concurrency, e.g., hoare's channels and tuple spaces. There are library implementations of these concepts (I believe) but they are not necessarily production-ready, well understood by the masses, or otherwise fit for commercial use. You'll need to go to other languages, e.g, go, for those.

    @TwitchTV, @Youtube: master-level zerg ladder/customs, commentary, and random miscellany.
This discussion has been closed.