multi-thread programming problem

Discussion in 'Mac Programming' started by jerrylying, Aug 14, 2008.

  1. jerrylying macrumors newbie

    Joined:
    Aug 14, 2008
    #1
    hi guys

    I met a problem when I was trying to use NSThread to sleep and wake up a thread. Because I am doing a porting job so I have to wirte some functions as interfaces between C++ and objective-c, and these functions are used to create, sleep, wake up and kill thread. I have implemented createThread() and killThread(), and they work well. But I don't know how to write sleepThread() and wakeupThread(), because the created thread should be sleeped and woke up by the main process but not the timer, so I am afraid the sleepForTimeInterval: and sleepUntilDate: won't work. could you guys give me a hand? Thanks a lot. And sorry for my poor English, I cant find enough info on my country's web site, and I hope you guys could understand what I am saying about.

    and here is my code

    class A //the c++ class
    {
    static void Func(void* p) { while(1) dosomething; }; //function in thread
    }

    @interface MacThread
    {
    NSThread* thread;
    }
    @end

    @implementation MacThread
    -(void)asThread
    {
    A::Func();
    }

    -(void) createThread: (unsigned int) stackSize
    {
    thread = [[NSThread alloc]initWithTarget:self selector:mad:selector(asThread) object:nil];
    [thread setStackSize:stackSize];

    return;
    }

    -(void) startThread
    {
    [thread start];
    }

    -(void) sleepThread
    {
    //need your help
    }

    -(void) wakeupThread
    {
    //need your help
    }

    -(void) killThread
    {
    [thread cancel];
    return;
    }
    @end

    //followings are interfaces invoked in C++
    void* cCreateThread(unsigned int stackSize)
    {
    MacThread *mThread = [MacThread alloc];
    [mThread createThread:stackSize];
    return (void*) mThread;
    }

    void cStartThread(void* thread)
    {
    MacThread *mThread = (MacThread*) thread;
    [mThread startThread];
    return;
    }

    void cSleepThread(void* thread)
    {
    //need your help
    }

    void cWakeupThread(void* thread)
    {
    //need your help
    }

    This is my first time posting here, thanks a lot again ^^
     
  2. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    I'm not sure why sleepForTimeInterval won't work for sleeping, but you will not be able to wake a thread early using NSThread.

    Why do you need to do this? You should be able to trigger action from threads that have been started by using mutexes (NSLocks), that you release when you're ready for a thread or threads to perform some action.

    It may be a little cleaner for you to divide your Objective-C and C++. Is A::func() a static method? If so, is there a reason this couldn't just be a C/Obj-C method and must be a C++ class method? Does the class have a number of static fields that must be referenced?

    -Lee
     
  3. jerrylying thread starter macrumors newbie

    Joined:
    Aug 14, 2008
    #3
    Yes, sleepForTimeInterval could sleep the thread for a while, but what I exactly need is I could wake up the thread whenever I want, so I am afraid sleepForTimeInterval is not fit to me.

    A::func() is a static method, the original class is a huge class in my project, so here I just use class A to instead. As I told before, I am porting a project to iphone, so I don't wanner to change the project's structure, you know that may cause some unexcepted errors.

    Thanks for your reply
     
  4. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #4
    Unfortunately you'll be unable to wake on demand with NSThread. You might need to stick to pthreads (which as far as I know should be fine).

    You could also rig it up with an NSLock like i mentioned, and have your children wait for a lock to be released to do the work, check the lock in a loop if necessary, etc. to control if the thread should be running or not.

    -Lee
     
  5. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #5
    I think NSConditionLock might do what you need.
     
  6. JVene macrumors newbie

    Joined:
    Jul 22, 2008
    #6
    Yes, the OP needs to visit the developer.apple.com site and search for NSCondition (a google gets you there, too) - and to read on the related materials.

    I don't think there's a significant benefit to using NSCondition over Unix (Posix) methods for this. Conditions and signals have been around for a long time, and since Mac is Unix, and since it's VERY likely that NSCondition and NSThread boil down to object oriented wrappers (in objective-C) for underlying OS services, it may be unwarranted.

    I say this because NSCondition and NSThread IS warranted to an objective-C programmer using C as the 'backing' language, where objects would otherwise not be available to provide leverage in accessing thread services.

    However, C++ has "RAII" idioms, which aren't in objective-C, and that makes thread work far more reliable. It would be faster and conceptually less involved to consider using boost with C++ for thread support, conditions and signals, as a C++ library support for an objective-C++ application.

    Using C++ to encapsulate and objective-C set of objects which in turn serve OS services doesn't seem efficient to me. The only reason to use such an approach would be if there was some need for NSxxx classes in conjunction with OTHER code in objective-C that depends upon them.


    In any event, the design pattern or algorithmic pattern the OP is looking for is simply a 'wait' on a condition.

    What the OP is suggesting as "sleep" is, instead, "wait" - on a condition object which can be signaled.

    Any other thread calling that signal (setting the signal) would release the thread.

    It may be important to note, too, for performance critical situations, that the release isn't immediate. It's close, and for most practical purpose is immediate. However, what usually happens (and this is somewhat different for the various OS implementations, I haven't check on Mac's underlying FreeBSD specs on this) the thread that is signaled is SCHEDULED for activation.

    This is the same as what happens when a lock on a mutex is attempted when it is already locked by another thread, and the 'attemptor' is put into a waiting state. When the owning thread releases the lock, the waiting thread is not released immediately, it is SCHEDULED for activation.

    This means that it will jump into action when the operating system's scheduler gets around to giving that thread some CPU attention.

    Many modern OS's switch somewhere in the range of 100,000 times per second (but this depends on a great many factors, including the hardware).

    That being the case, if you expected 'releases' to be immediate, especially on locks but also on 'waits' for a signal, and if you timed many successive releases, you might expect very efficient code to 'release' millions of times per second, but it won't. The releases will occur at the speed of the OS task switch at best, divided by the number of threads and processes, and further complicated by the scheduling algorithm's and priorities of the threads themselves.

    For single response situations (most common, just signaling a thread so it jumps into action) this is generally fast enough, and much faster than launching some external process.

    The primary reason for having a thread waiting on a signal is to create a queue. This way you can stuff jobs into the queue and let it get around to them as it can. If it's quite busy, calling code would simply be adding some function description into the queue - using a list or array representing a deque or circular queue storage.

    I point this out because it's an important design pattern - representing a queue as a container of functions. It's important to know what will happen if your queue is signaled while it's busy. If you create threads for specific purposes, and that's the only reason said thread exists (and this is generally rare), then you may know by design that this can't happen.

    Usually, however, it does. This means you must establish a means of reacting to this by design. If you take this to the logical extension, it means you create general purpose thread queues that are waiting for any task you hand to them, and they're highly reusable. These notions are a natural extension of the OP's original question; it becomes obvious after several years, when you've done it over and over, and realize if you just had some general purpose thread you can stuff jobs into, you'd be able to thread things without much hassle setting it up.
     

Share This Page