Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

The merits of Nazi threads

Options
  • 01-09-2003 3:29pm
    #1
    Closed Accounts Posts: 5,564 ✭✭✭


    Proposition

    accept client connection
    thread();
    thread(2);

    thread2 a nazi thread[1] - sleep for thirty seconds and then will unambiguously kill the first thread.

    I have come up with this technique for client connections that get really, really slow in thread one, and go past a certain lifespan, so that I can terminate all threads-of-type-1 unambiguously and never have an instance where a thread has become stuck by a zombised client connection.

    Opinions on this methodology?



    [1]Naming conventions may vary.


Comments

  • Closed Accounts Posts: 437 ✭✭casper-


    Hmm .. it's kinda hard to comment without knowing a little bit more of what's going on. What's the application, and what language are you using? I will say one thing though, for most server apps spawning a thread for each client (much less two) to handle a connection is not really a scalable architecture. Again though, I have no idea what your program is supposed to do :)


  • Registered Users Posts: 16,413 ✭✭✭✭Trojan


    What kind of threads are they (pthreads)?
    Originally posted by jedidjab79
    Hmm .. it's kinda hard to comment without knowing a little bit more of what's going on. What's the application, and what language are you using? I will say one thing though, for most server apps spawning a thread for each client (much less two) to handle a connection is not really a scalable architecture. Again though, I have no idea what your program is supposed to do :)

    Yeah, not mad scalable.

    Have you implemented it? Give us real code.

    Al.


  • Closed Accounts Posts: 5,564 ✭✭✭Typedef


    I have a closed source search engine, which has C API.

    This engine is replacing PGSQL for searching on my companies website.

    The website runs php, and there is no PHP available port for the engine.
    Problem:

    Betwixt the programming department here and their side we came up with an XML-RPC based searching paradigm, which is fine.

    The thing is I came up with the idea of simply writing our own TCP protocol to operate over sockets to chuck the data to and from the server.

    The performance increase bewtixt a simple data transation over TCP and XML-RPC via HTTP is roughly six times the speed increase on the in house TCP specification.

    It must be possible to support multiple concurrent connection instances in a fairly 'scaleable' fashion.

    Thus the choice's are.
    Monolithic socket daemon : running multiple instaces on different ports.
    Threading.
    Forking.

    I specifically didn't go with forking, because ... it seemed like overkill to have a sperate process. It's difficult to say which paradigm I prefer at this stage... and I might end up falling back to XMLRPC.

    But, simply doing a select(); on my sockets is no good, since (a) I might get a zombiesed send-recv... which would leave the daemon nuked. Plus, the protocol being used does this.

    Client - > content length blah, rpc function blah.
    Server -> ok
    Client -> data
    Server -> content length blah
    Client -> ok
    Server -> data

    End of transaction, so attempting to force this sort of transaction through select(), might be possible, but would I suspect be messy.

    For just this sort of reason, forking becomes attractive, though I suspect the overhead for a thread is a hell of a lot less then that of a totally seperate process instance.

    So the logic is.
    thread for each connection instance
    and then thread again.

    If the client manages to zombise the first thread, this is irrelevant, since the nazi_thread(); should come along, kill thread 1 and then terminate itself, all of which happens in a seperate execution context, thus allowing for multiple concurrent transaction instances.

    Or am I making no sense?


  • Closed Accounts Posts: 5,564 ✭✭✭Typedef


    void networking::networking_do_loop(){
        /*Main loop to accept connections and call the search functions*/
        int state,b,num_bytes,fd;
        sigset_t sigs;
        socklen_t slen;
        char incoming[22];
        MAX_FD=0;
        trans_t tr;
                                                                                                                                                       
        tr.iMaxDocs=iMaxDocs;
        tr.iWeight=iWeight;
        strncpy(tr.cRWServer,cRWServer,1024);
        strncpy(tr.pgstr,pgstr,1024);
        #if defined(DEBUG)
        syslog(LOG_NOTICE,"Object vales %s %s %d %d\n",
                tr.cRWServer,tr.pgstr,tr.iMaxDocs,tr.iWeight);
        #endif
        while(1){
            fd=accept(srv_skfd,(struct sockaddr*)&cli,&slen);
            #if defined(DEBUG)
                    syslog(LOG_NOTICE,"Accepted client connection on %d \n",fd,MAX_FD);
            #endif
            tr.skfd=fd;
            /*Create a separate thread for each separate connection instance!
             *Then create a second thread thread_nazi(); to umambiguously kill the firs thread after 30 seconds
             */
            #if defined(DEBUG)
                    syslog(LOG_NOTICE,"Creating execution context for ID:%d : thead_id %d\n",b,thread_dref[fd]);
            #endif
            sigemptyset(&sigs);
            sigaddset(&sigs,SIGRTMIN);
            pthread_sigmask(SIG_UNBLOCK,&sigs,0);
            pthread_create(&thread_dref[fd],0,socket_thread,&tr);
            pthread_create(&nazi_dref[fd],0,thread_nazi,&thread_dref[fd]);
        }
     return;
    };
    
    
    typedef struct trans{
    char pgstr[LOCAL_MAX_STRLEN];
    char cRWServer[LOCAL_MAX_STRLEN];
    int skfd;
    int iMaxDocs;
    int iWeight;
    }trans_t;
    
    
    void*socket_thread(void*handle){
                                                                                                                                                       
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
        trans_t tr=(*(trans_t*)handle);
        int skfd=tr.skfd;
        #if defined(DEBUG)
        syslog(LOG_NOTICE,"THREAD:skfd %d MaxDocs %d Server %s\n",
               skfd,tr.iMaxDocs,tr.cRWServer);
        #endif
                                                                                                                                                       
        tno tno_object;
        tno_object.iMaxDocs=tr.iMaxDocs;
        tno_object.iWeight=tr.iWeight;
        strncpy(tno_object.pgstr,tr.pgstr,1024);
        strncpy(tno_object.cRWServer,tr.cRWServer,1024);
                                                                                                                                                       
        tno_object.tno_command_parse(skfd);
        #if defined(DEBUG)
            syslog(LOG_NOTICE,"Socket_thread : Exiting thread for socket %d\n",skfd);
        #endif
        pthread_detach(pthread_self());
        pthread_exit(0);
    return 0;
    };
    void*thread_nazi(void*watch){
                                                                                                                                                       
        #if defined(DEBUG)
            syslog(LOG_NOTICE,"Thread nazi : running\n");
        #endif
        pthread_t thread_id=(*(pthread_t*)watch);
        sleep(30);  /*Sleep for thirty seconds*/
                                                                                                                                                       
        #if defined(DEBUG)
            syslog(LOG_NOTICE,"Thread nazi : Canceling thread if exists execution context : %d\n",thread_id);
        #endif
        pthread_detach(thread_id);
        pthread_cancel(thread_id);
        //close(thread_id);           /*Thread and socket id are the same*/
        #if defined(DEBUG)
            syslog(LOG_NOTICE,"Thread nazi : Exiting self now!!\n");
        #endif
        pthread_detach(pthread_self());
        pthread_exit(0);
    return 0;
    };
    
                                                                                                                                                       
    void tno:: parse_command(int skfd){
    //do some stuff;
    return;
    }
    
    


  • Registered Users Posts: 15,443 ✭✭✭✭bonkey


    Originally posted by Typedef
    I have come up with this technique for client connections that get really, really slow in thread one, and go past a certain lifespan, so that I can terminate all threads-of-type-1 unambiguously and never have an instance where a thread has become stuck by a zombised client connection.

    I know SFA about pthreads on Linux systems, but wouldn't it be neater and more efficient to have a single "assassin" thread, which monitored all type 1 threads, rather than one-for-one as you describe here?

    OK - the assassin would be more complex than your nazis, but once you start scaling at all, that should quickly be negated by the fact that there's only one of it.

    Just a thought.

    jc


  • Advertisement
  • Closed Accounts Posts: 5,564 ✭✭✭Typedef


    Originally posted by bonkey
    I know SFA about pthreads on Linux systems, but wouldn't it be neater and more efficient to have a single "assassin" thread, which monitored all type 1 threads, rather than one-for-one as you describe here?

    I guess.

    The assassin could for example sleep for one second.... and keep an array of time indexes for each thread and destroy any thread which had gone past time(x).

    What would irk me about that is how to determine if a thread is running or not....
    I'm not totally sure how that is done, but AFAIK, calling pthread_cancel(); is safe on a terminated thread.... though first determining if a thread (needs) termination would admitadely be neater...
    If someone knows how that is done, in the context of no-access to program level superglobals (because this craps out \#include calls) to multiple files, then fess up.

    Though two concurrent execution streams... one creating new threads... and one monitoring created threads.. is something I'll have a think about... and see if (a) I can do it and (b) if it gives an advantage in terms of stability and speed.


Advertisement