thread 订阅
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。一个进程可以有很多线程,每条线程并行执行不同的任务。在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。 展开全文
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。一个进程可以有很多线程,每条线程并行执行不同的任务。在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。
信息
提出者
dozer
定    义
程序执行流的最小单元
多线程中
CPU的基本单位
应用学科
计算机
中文名
线程
外文名
thread
别    称
执行绪;轻量进程
线程发展简史
线程的引入:60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。因此在80年代,出现了能独立运行的基本单位——线程(Threads)。
收起全文
精华内容
下载资源
问答
  • JAVA报错Exception in thread “main” java.lang.NullPointerException 我在编写一个需要使用对象数组的代码发现了这个问题。 情况是:我在定义完一个对象数组后,打算给数组的各个元素对象赋值时,出现了报错 在...

    JAVA报错Exception in thread “main” java.lang.NullPointerException

    我在编写一个需要使用对象数组的代码发现了这个问题。

    情况是:我在定义完一个对象数组后,打算给数组的各个元素对象赋值时,出现了报错
    在这里插入代码片 Exception in thread "main" java.lang.NullPointerException at 对象数组.Str.main(Str.java:11)
    出现问题的原因:
    因为在我们定义的对象数组中,每一个元素都是一个对象,既然是对象肯定就要分配内存啊!部分人忽略了这个问题,所以才有了上面的错误。
    解决方法
    给对象数组中的每一个元素对象分配内存
    操作:对象[i]=new 对象的类名();

    举例:我自己的例子
    1.我定义一个类,类名为People,类里面只有一个变量age

    2.我再定义了一个Peopled的对象数组,长度为5个元素
    People [] young=new People[5];
    3.接下来我给对象数组中的每一个元素对象分配内存
    for(int i=0;i<5;i++) {
    young[i]=new People(); //分配内存
    young[i].age=a[i]; //给People数组中的每个元素赋值
    }
    问题解决了!

    下面是具体代码
    没有修改之前的代码:

    public class Str {
    	public static void main(String[] args) {
    		
    		int [] a= {16,17,18,19,18};
    		
    		People [] young=new People[5];//创建一个对象数组
    		
    		for(int i=0;i<5;i++) {
    			young[i].age=a[i];	//给People数组中的每个元素赋值
    		}
    		
    		for(int i=0;i<5;i++) {		//检验结果
    			System.out.print(young[i]);
    		}
    	}
    }
    
    class People{
    	int age;
    }
    

    修改后的代码:

    package 对象数组;
    
    public class Str {
    	public static void main(String[] args) {
    		
    		int [] a= {16,17,18,19,18};
    		
    		People [] young=new People[5];//创建一个对象数组
    		
    		for(int i=0;i<5;i++) {
    			young[i]=new People();			//给每个元素分配内存
    			young[i].age=a[i];	//给People数组中的每个元素赋值
    		}
    		
    		for(int i=0;i<5;i++) {		//检验结果
    			System.out.print(young[i].age+",");
    		}
    	}
    }
    
    class People{
    	int age;
    }
    

    运行结果:
    16,17,18,19,18,

    展开全文
  • Android ThreadthreadLoop方法

    千次阅读 2018-04-12 17:27:54
    Android Framework中的线程Thread及它的threadLoop方法 在Framework中的Thread普遍的特点就是有一个 threadLoop方法。它到底是怎么循环起来的。 Android中java世界的Thread 先来看看java是怎么创建一个线程的。...

    Android Framework中的线程Thread及它的threadLoop方法

    在Framework中的Thread普遍的特点就是有一个 threadLoop方法。它到底是怎么循环起来的。

    Android中java世界的Thread

    先来看看java是怎么创建一个线程的。这个是最舒服的,也是我最熟悉的。

    new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                    ...
            }
    }).start();

    当然,你也可以在android中创建一个消息循环的HandlerThread

    HandlerThread mThread = new HandlerThread("test");
    mThread.start();
    Handler mHandler = new Handler(mThread.getLooper()){
    
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stubsuper.handleMessage(msg);
            }
    };

    上面中通过mHandler发送消息就可以在mThread中处理了,并且这个mThread不是UIThread,不会阻塞主线程。

    Linux下c语言的Thread

    java世界的Thread很方便,那么c呢?
    Android基于linux所以,多线程编程也应该基于linux下的多线程。linux下的c语言用pthread。大家可以看这篇文章。
    linux下C/C++,多线程pthread
    我把里面的例子改良了一下
    test.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <unistd.h>
    void *test(void *ptr)
    {
        int i;
        for(i=0;i<8;i++)
        {
            printf("the pthread running ,count: %d\n",i);
            sleep(1); 
        }
    
    }
    
    
    int main(void)
    {
        pthread_t pId;
        int i,ret;
        ret = pthread_create(&pId,NULL,test,NULL);
    
        if(ret != 0)
        {
            printf("create pthread error!\n");
            exit(1);
        }
    
        for(i=0;i < 5;i++)
        {
            printf("main thread running ,count : %d\n",i);
            sleep(1);
        }
    
        printf("main thread will exit when pthread is over\n");
        pthread_join(pId,NULL);
        printf("main thread  exit\n");
    
        return0;
    
    }

    然后编译

    gcc -o test test.c -lpthread./test
    

    运行结果如下:

    main thread running ,count : 0the pthread running ,count: 0
    main thread running ,count : 1the pthread running ,count: 1
    main thread running ,count : 2the pthread running ,count: 2
    main thread running ,count : 3the pthread running ,count: 3
    main thread running ,count : 4the pthread running ,count: 4
    main thread will exit when pthread isoverthe pthread running ,count: 5the pthread running ,count: 6the pthread running ,count: 7
    main thread  exit

    例子比较简单,主要是创建一个线程,然后主线程等待子线程运行完毕再退出。

    Android Framework中的Thread

    下面焦点回到文章的主题当中,我们来看看Framework中常用的Thread是个何种形态。
    先看看活生生的例子。
    在源码中搜索threadLoop,当然也可以搜索thread,然后随便挑选一个Thread子类进行研究。这里挑了
    /frameworks/av/services/audioflinger/AudioWatchdog.h

    #ifndef AUDIO_WATCHDOG_H
    #define AUDIO_WATCHDOG_H
    #include <time.h>
    #include <utils/Thread.h>
    
    namespace android {
    
    ......
    
    class AudioWatchdog : public Thread {
    
    public:
        AudioWatchdog(unsigned periodMs = 50) : Thread(false/*canCallJava*/), mPaused(false),
                mPeriodNs(periodMs * 1000000), mMaxCycleNs(mPeriodNs * 2),
                // mOldTs// mLogTs initialized below
                mOldTsValid(false), mUnderruns(0), mLogs(0), mDump(&mDummyDump)
            {
                #define MIN_TIME_BETWEEN_LOGS_SEC 60// force an immediate log on first underrun
                mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC;
                mLogTs.tv_nsec = 0;
            }
        virtual         ~AudioWatchdog() { }
        // Do not call Thread::requestExitAndWait() without first calling requestExit().
        // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.virtualvoid        
        requestExit();
    
        // FIXME merge API and implementation with AudioTrackThreadvoid            
        pause();        // suspend thread from execution at next loop boundaryvoid            
        resume();       // allow thread to execute, if not requested to exit
        // Where to store the dump, or NULL to not updatevoid            
        setDump(AudioWatchdogDump* dump);
    
    private:
        virtual bool threadLoop();
    
        Mutex           mMyLock;        // Thread::mLock is private
        Condition       mMyCond;        // Thread::mThreadExitedCondition is privatebool            mPaused;        // whether thread is currently paused
    
        ......
    };
    
    }   // namespace android#endif  // AUDIO_WATCHDOG_H

    我们可以看到AudioWatchDog确实是Thread的子类,那好,下面看实现。
    /frameworks/av/services/audioflinger/AudioWatchdog.cpp

    #define LOG_TAG "AudioWatchdog" //#define LOG_NDEBUG 0
    #include <utils/Log.h>
    #include "AudioWatchdog.h"
    namespace android {
    
    void AudioWatchdogDump::dump(int fd)
    {
        char buf[32];
        if (mMostRecent != 0) {
            // includes NUL terminator
            ctime_r(&mMostRecent, buf);
        } else {
            strcpy(buf, "N/A\n");
        }
        fdprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
                mUnderruns, mLogs, buf);
    }
    
    bool AudioWatchdog::threadLoop()
    {
        {
            AutoMutex _l(mMyLock);
            if (mPaused) {
                mMyCond.wait(mMyLock);
                // ignore previous timestamp after resume()
                mOldTsValid = false;
                // force an immediate log on first underrun after resume()
                mLogTs.tv_sec = MIN_TIME_BETWEEN_LOGS_SEC;
                mLogTs.tv_nsec = 0;
                // caller will check for exitPending()returntrue;
            }
        }
        struct timespec newTs;
        int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
        if (rc != 0) {
            pause();
            returnfalse;
        }
        if (!mOldTsValid) {
            mOldTs = newTs;
            mOldTsValid = true;
            returntrue;
        }
        time_t sec = newTs.tv_sec - mOldTs.tv_sec;
        long nsec = newTs.tv_nsec - mOldTs.tv_nsec;
        if (nsec < 0) {
            --sec;
            nsec += 1000000000;
        }
        mOldTs = newTs;
        // cycleNs is same as sec*1e9 + nsec, but limited to about 4 seconds
        uint32_t cycleNs = nsec;
        if (sec > 0) {
            if (sec < 4) {
                cycleNs += sec * 1000000000;
            } else {
                cycleNs = 4000000000u;
            }
        }
        mLogTs.tv_sec += sec;
        if ((mLogTs.tv_nsec += nsec) >= 1000000000) {
            mLogTs.tv_sec++;
            mLogTs.tv_nsec -= 1000000000;
        }
        if (cycleNs > mMaxCycleNs) {
            mDump->mUnderruns = ++mUnderruns;
            if (mLogTs.tv_sec >= MIN_TIME_BETWEEN_LOGS_SEC) {
                mDump->mLogs = ++mLogs;
                mDump->mMostRecent = time(NULL);
                ALOGW("Insufficient CPU for load: expected=%.1f actual=%.1f ms; underruns=%u logs=%u",
                    mPeriodNs * 1e-6, cycleNs * 1e-6, mUnderruns, mLogs);
                mLogTs.tv_sec = 0;
                mLogTs.tv_nsec = 0;
            }
        }
        struct timespec req;
        req.tv_sec = 0;
        req.tv_nsec = mPeriodNs;
        rc = nanosleep(&req, NULL);
        if (!((rc == 0) || (rc == -1 && errno == EINTR))) {
            pause();
            returnfalse;
        }
        returntrue;
    }
    
    void AudioWatchdog::requestExit()
    {
        // must be in this order to avoid a race condition
        Thread::requestExit();
        resume();
    }
    
    void AudioWatchdog::pause()
    {
        AutoMutex _l(mMyLock);
        mPaused = true;
    }
    
    void AudioWatchdog::resume()
    {
        AutoMutex _l(mMyLock);
        if (mPaused) {
            mPaused = false;
            mMyCond.signal();
        }
    }
    
    void AudioWatchdog::setDump(AudioWatchdogDump *dump)
    {
        mDump = dump != NULL ? dump : &mDummyDump;
    }
    
    }   // namespace android

    很明显,它的核心方法就是threadLoop(),但是它是怎么启动的呢?又是怎么循环运行的呢?带着疑问我又在源码中搜索关键字AudioWatchdog
    结果发现有两个地方引用了。

    /frameworks/av/services/audioflinger/AudioFlinger.h
    /frameworks/av/services/audioflinger/AudioFlinger.cpp

    在AudioFlinger.h中MixerThread中有个AudioWatchdog的sp对象

     class MixerThread : public PlaybackThread {
        public:
            MixerThread (const sp<AudioFlinger>& audioFlinger,
                         AudioStreamOut* output,
                         audio_io_handle_t id,
                         audio_devices_t device,
                         type_t type = MIXER);
            virtual             ~MixerThread();
    
    
        protected:
                        AudioMixer* mAudioMixer;    // normal mixerprivate:
                        sp<AudioWatchdog> mAudioWatchdog; // non-0 if there is an audio watchdog thread
        };

    我们再看代码
    /frameworks/av/services/audioflinger/AudioFlinger.cpp

    AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
            audio_io_handle_t id, audio_devices_t device, type_t type)
            :PlaybackThread(audioFlinger, output, id, device, type),
            // mAudioMixer below// mFastMixer below
            mFastMixerFutex(0)
            // mOutputSink below// mPipeSink below// mNormalSink below
    {
    
    ......
    #ifdef AUDIO_WATCHDOG
            // create and start the watchdog
            mAudioWatchdog =new AudioWatchdog();
            mAudioWatchdog->setDump(&mAudioWatchdogDump);
            mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
            tid = mAudioWatchdog->getTid();
            err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
            if (err !=0) {
                ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
                        kPriorityFastMixer, getpid_cached, tid, err);
            }
    #endif......
    }

    删掉不相关代码,我们看到AudioWatchdog对象确实创建了,并且调用了它的run方法。在java中Thread的run方法就是启动, 这个也应该如此。但是如之前的源码所示AudioWatchdog.cpp中并没有实现run方法,怎么办呢?别紧张,它还有父类Thread.

    /frameworks/native/include/utils/Thread.h

    #ifndef _LIBS_UTILS_THREAD_H
    #define _LIBS_UTILS_THREAD_H
    #include <stdint.h>
    #include <sys/types.h>
    #include <time.h>
    #if defined(HAVE_PTHREADS)
    # include <pthread.h>
    #endif
    #include <utils/Condition.h>
    #include <utils/Errors.h>
    #include <utils/Mutex.h>
    #include <utils/RefBase.h>
    #include <utils/Timers.h>
    #include <utils/ThreadDefs.h>// ---------------------------------------------------------------------------
    namespace android {
    // ---------------------------------------------------------------------------
    
    class Thread : virtual public RefBase
    {
    public:
        // Create a Thread object, but doesn't create or start the associated
        // thread. See the run() method.
        Thread(bool canCallJava = true);
        virtual             ~Thread();
    
        // Start the thread in threadLoop() which needs to be implemented.virtual status_t  run(    constchar* name = 0, int32_t priority = PRIORITY_DEFAULT, size_t stack = 0);
    
        // Ask this object's thread to exit. This function is asynchronous, when the// function returns the thread might still be running. Of course, this// function can be called from a different thread.virtualvoid        requestExit();
    
        // Good place to do one-time initializationsvirtual status_t    readyToRun();
    
        // Call requestExit() and wait until this object's thread exits.// BE VERY CAREFUL of deadlocks. In particular, it would be silly to call// this function from this object's thread. Will return WOULD_BLOCK in// that case.
                status_t    requestExitAndWait();
    
        // Wait until this object's thread exits. Returns immediately if not yet running.// Do not call from this object's thread; will return WOULD_BLOCK in that case.
                status_t    join();
    
    #ifdef HAVE_ANDROID_OS// Return the thread's kernel ID, same as the thread itself calling gettid() or// androidGetTid(), or -1 if the thread is not running.
                pid_t       getTid() const;
    #endifprotected:
        // exitPending() returns trueifrequestExit() has been called.
                boolexitPending() const;
    
    private:
        // Derived class must implement threadLoop(). The thread starts its life
        // here. There are two ways of using the Thread object:
        // 1) loop: if threadLoop() returns true, it will be called again if
        //          requestExit() wasn't called.
        // 2) once: if threadLoop() returns false, the thread will exit upon return.
        virtual bool threadLoop() = 0;
    
    private:
        Thread& operator=(const Thread&);
        staticint             _threadLoop(void* user);
        constbool            mCanCallJava;
        // always hold mLock when reading or writing
                thread_id_t     mThread;
        mutable Mutex           mLock;
                Condition       mThreadExitedCondition;
                status_t        mStatus;
        // note that all accesses of mExitPending and mRunning need to hold mLockvolatilebool           mExitPending;
        volatilebool           mRunning;
                sp<Thread>      mHoldSelf;
    #ifdef HAVE_ANDROID_OS// legacy for debugging, not used by getTid() as it is set by the child thread// and so is not initialized until the child reaches that point
                pid_t           mTid;
    #endif
    };
    
    
    }; // namespace android// ---------------------------------------------------------------------------#endif // _LIBS_UTILS_THREAD_H// 

    可以看到确实有run方法。
    status_t Thread::run(const char* name, int32_t priority, size_t stack)
    {
    Mutex::Autolock _l(mLock);

    if (mRunning) {
        // thread already started
        return INVALID_OPERATION;
    }
    
    // reset status and exitPending to their default value, so we can
    //try again after an error happened (either below, orin readyToRun())
    mStatus = NO_ERROR;
    mExitPending = false;
    mThread = thread_id_t(-1);
    
    // hold a strong reference on ourself
    mHoldSelf = this;
    
    mRunning = true;
    
    bool res;
    if (mCanCallJava) {
        res = createThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    } else {
        res = androidCreateRawThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    }
    
    if (res == false) {
        mStatus = UNKNOWN_ERROR;   // something happened!
        mRunning = false;
        mThread = thread_id_t(-1);
        mHoldSelf.clear();  //"this" may have gone away after this.
    
        return UNKNOWN_ERROR;
    }
    
    // Do not refer to mStatus here: The thread is already running (may, in fact
    // already have exited with a valid mStatus result). The NO_ERROR indication
    // here merely indicates successfully starting the thread and does not// imply successful termination/execution.
    return NO_ERROR;
    
    // Exiting scope of mLock is a memory barrier and allows new thread to run
    

    }

    run()方法中有这么一段

    if (mCanCallJava) {
            res = createThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        } else {
            res = androidCreateRawThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        }

    mCanCallJava的意思是能不能被JNI层调用,然后根据值去创建Thread,这里有两个分支,我们就选择createThreadEtc()
    最终代码会走到这里

    int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
                                   void *userData,
                                   const char* threadName,
                                   int32_t threadPriority,
                                   size_t threadStackSize,
                                   android_thread_id_t *threadId)
    {
        ......
            entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
            userData = t;
        }
    #endifif (threadStackSize) {
            pthread_attr_setstacksize(&attr, threadStackSize);
        }
    
        errno = 0;
        pthread_t thread;
        int result = pthread_create(&thread, &attr,
                        (android_pthread_entry)entryFunction, userData);
        pthread_attr_destroy(&attr);
        if (result != 0) {
            ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n""(android threadPriority=%d)",
                entryFunction, result, errno, threadPriority);
            return0;
        }
    
        ......
        return1;
    }

    删除了不相关代码,大家看看是不是很熟悉啊。我在文章开始的部分就写出了linux下c语言pthread创建线程的例子,大家可以回头看看。也就 是pthread_create()。这里面传进来的entryFunction是Thread中的_threadLoop()

    int Thread::_threadLoop(void* user)
    {
        Thread* const self= static_cast<Thread*>(user);
    
        sp<Thread> strong(self->mHoldSelf);
        wp<Thread> weak(strong);
        self->mHoldSelf.clear();
    
    #ifdef HAVE_ANDROID_OS
        // this is very useful for debugging with gdbself->mTid = gettid();
    #endif
    
        bool first =true;
    
        do {
            bool result;
            if (first) {
                first =false;
                self->mStatus =self->readyToRun();
                result = (self->mStatus == NO_ERROR);
    
                if (result &&!self->exitPending()) {
                    // Binder threads (and maybe others) rely on threadLoop// running at least once after a successful ::readyToRun()// (unless, of course, the thread has already been asked to exit// at that point).// This is because threads are essentially used like this://   (new ThreadSubclass())->run();// The caller therefore does not retain a strong reference to// the thread and the thread would simply disappear after the// successful ::readyToRun() call instead of entering the// threadLoop at least once.
                    result =self->threadLoop();
                }
            } else {
                result =self->threadLoop();
            }
    
            // establish a scope for mLock
            {
            Mutex::Autolock _l(self->mLock);
            if (result ==false||self->mExitPending) {
                self->mExitPending =true;
                self->mRunning =false;
                // clear thread ID so that requestExitAndWait() does not exit if// called by a new thread using the same thread ID as this one.self->mThread = thread_id_t(-1);
                // note that interested observers blocked in requestExitAndWait are// awoken by broadcast, but blocked on mLock until break exits scopeself->mThreadExitedCondition.broadcast();
                break;
            }
            }
    
            // Release our strong reference, to let a chance to the thread// to die a peaceful death.
            strong.clear();
            // And immediately, re-acquire a strong reference for the next loop
            strong = weak.promote();
        } while(strong !=0);
    
        return0;
    }

    _threadLoop()这个方法就是Thread的最大秘密,它是一个while循环。
    1、创建线程时,会sp和wp一次线程本身。
    2、如果是第一次执行会运行线程的readyToRun()方法,再执行threadLoop(),否则,直接运行threadLoop()。
    3、threadLoop()方法有返回值,如果threadLoop()返回false的时候,线程会做清理工作,然后退出while循环,结束运行。

    所以在这里,我开始时的疑问—为什么线程Thread中的threadLoop()能够循环处理数据就到此做了说明。Thread被创 建,Thread中的run被调用,__threadLoop()被调用,readyToRun()被调用,然后循环调用threadLoop()。并且 在threadLoop()返回false时,可以退出循环。

    特殊情况

    有的时候Android Framework中Thread的run()方法很难发现在哪里被调用。如SurfaceFlinger它也是一个Thread子类。在源码中搜索可以发现它的创建位置

    class SurfaceFlinger : public BinderService<SurfaceFlinger>,
                           public BnSurfaceComposer,
                           private IBinder::DeathRecipient,
                           private Thread,
                           private HWComposer::EventHandler
    {
    public:
        staticcharconst* getServiceName() {
            return"SurfaceFlinger";
        }
    
        SurfaceFlinger();
    
    
        /* ------------------------------------------------------------------------
         * Thread interface
         */virtualbool threadLoop();
        virtual status_t readyToRun();
        virtualvoid onFirstRef();
    
    
    };
    
    // ---------------------------------------------------------------------------
    }; // namespace android#endif // ANDROID_SURFACE_FLINGER_H

    去找它创建的地方
    /frameworks/base/cmds/system_server/library/system_init.cpp

    extern"C" status_t system_init()
    {
        ALOGI("Entered system_init()");
    
        sp<ProcessState> proc(ProcessState::self());
    
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p\n", sm.get());
    
    
    
        char propBuf[PROPERTY_VALUE_MAX];
        property_get("system_init.startsurfaceflinger", propBuf, "1");
        if (strcmp(propBuf, "1") == 0) {
            // Start the SurfaceFlinger
            SurfaceFlinger::instantiate();
        }
    
    
        // And now start the Android runtime.  We have to do this bit// of nastiness because the Android runtime initialization requires// some of the core system services to already be started.// All other servers should just start the Android runtime at// the beginning of their processes's main(), before calling// the init function.
        ALOGI("System server: starting Android runtime.\n");
        AndroidRuntime* runtime = AndroidRuntime::getRuntime();
    
        ALOGI("System server: starting Android services.\n");
        JNIEnv* env = runtime->getJNIEnv();
        if (env == NULL) {
            return UNKNOWN_ERROR;
        }
        jclass clazz = env->FindClass("com/android/server/SystemServer");
        if (clazz == NULL) {
            return UNKNOWN_ERROR;
        }
        jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
        if (methodId == NULL) {
            return UNKNOWN_ERROR;
        }
        env->CallStaticVoidMethod(clazz, methodId);
    
        ALOGI("System server: entering thread pool.\n");
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
        ALOGI("System server: exiting thread pool.\n");
    
        return NO_ERROR;
    }

    我们可以看到

    SurfaceFlinger::instantiate();
    

    但它本身并没有实现instantiate()方法,那找它的父类。
    /frameworks/native/include/binder/BinderService.h

    namespaceandroid {
    
    template<typename SERVICE>
    classBinderService
    {public:
        static status_t publish(bool allowIsolated = false) {
            sp<IServiceManager> sm(defaultServiceManager());
            return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
        }
    
        static void publishAndJoinThreadPool(bool allowIsolated = false) {
            sp<IServiceManager> sm(defaultServiceManager());
            sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
            ProcessState::self()->startThreadPool();
            IPCThreadState::self()->joinThreadPool();
        }
    
        staticvoid instantiate() { publish(); }
    
        static status_t shutdown() {
            return NO_ERROR;
        }
    };
    
    
    }; // namespace android// ---------------------------------------------------------------------------#endif // ANDROID_BINDER_SERVICE_H

    会调用publish()方法。
    而SERVICE在这里是一个模板类。在这里SERVICE自然对应SurfaceFlinger
    所以publish()会向ServiceManager添加一个Service这个Service就是Surfaceflinger。
    然后我们看SurfaceFlinger的构造函数
    /frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    SurfaceFlinger::SurfaceFlinger()
        :   BnSurfaceComposer(), Thread(false),
            mTransactionFlags(0),
            mTransactionPending(false),
            mAnimTransactionPending(false),
            mLayersRemoved(false),
            mRepaintEverything(0),
            mBootTime(systemTime()),
            mVisibleRegionsDirty(false),
            mHwWorkListDirty(false),
            mDebugRegion(0),
            mDebugDDMS(0),
            mDebugDisableHWC(0),
            mDebugDisableTransformHint(0),
            mDebugInSwapBuffers(0),
            mLastSwapBufferTime(0),
            mDebugInTransaction(0),
            mLastTransactionTime(0),
            mBootFinished(false)
    {
        ALOGI("SurfaceFlinger is starting");
    
        // debugging stuff...charvalue[PROPERTY_VALUE_MAX];
    
        property_get("debug.sf.showupdates", value, "0");
        mDebugRegion = atoi(value);
    
        property_get("debug.sf.ddms", value, "0");
        mDebugDDMS = atoi(value);
        if (mDebugDDMS) {
            if (!startDdmConnection()) {
                // start failed, and DDMS debugging not enabled
                mDebugDDMS = 0;
            }
        }
        ALOGI_IF(mDebugRegion, "showupdates enabled");
        ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
    }

    可还是没有发现run()方法的影踪,没有办法只得去父类构造方法看
    结果发现也没有!!!
    没有办法,继续在源码中搜索SurfaceFlinger,结果发现与之相关的信息大多是sp
    就看看sp吧。
    sp是Android在c++中搞得类似java中弱引用、强引用的一套指针概念,那应该是方便回收吧。
    而Android Framework中的c++世界,RefBase这个类有点像java中的Object.
    而sp是一个模板类。

    总之调用sp时会调用SurfaceFlinger的onFirstRef()方法。
    那好,看代码吧

    void SurfaceFlinger::onFirstRef()
    {
        mEventQueue.init(this);
    
        run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
    
        // Wait for the main thread to be done with its initialization
        mReadyToRunBarrier.wait();
    }

    看见没有?run()方法在这里调用了。

    所以,在Framework中如果你找不到一个Thread在何处被启动,那么去它的onFirstRef()方法中去看看吧

    展开全文
  • 从小白到起飞的 RT-Thread 开发指南

    万次阅读 多人点赞 2020-12-26 03:56:51
    Hello,大家好,我是 RT-Thread 宣传委员(自封的)???? 我经常给大家安利 RT-Thread,尤其是那些还没用上 RT-Thread、在纠结选择哪个 RTOS、要不要学习 RTOS 的朋友。 RT-Thread 简介 RT-Thread 是什么 据不完全...

    Hello,大家好,我是 RT-Thread 宣传委员(自封的)🙂

    我经常给大家安利 RT-Thread,尤其是那些还没用上 RT-Thread、在纠结选择哪个 RTOS、要不要学习 RTOS 的朋友。

    1. RT-Thread 简介

    1.1 RT-Thread 是什么

    据不完全统计,世界有成千上万个 RTOS(Real-time operating system,实时操作系统),RT-Thread 就是其中一个优秀的作品。

    RT-Thread 内核的第一个版本是熊谱翔先生在 2006 年年初发布的 0.1 版本。因为 RTOS 中的任务更类似于通用操作系统中的线程,并且这个系统支持基于优先级的抢占式任务调度算法,调度器的时间复杂度是 O(1),所以把它命名为 RT-Thread,即实时线程。名字起得真妙 (。・∀・)ノ

    经过14年的发展,RT-Thread 被广泛应用于智能家居、智慧城市、安防、工控、穿戴等众多行业领域,累计装机量超过6亿台,GitHub 的 Star 数量超过 5.3k,嵌入式开源社区活跃度行业第一。

    在这里插入图片描述

    1.2 RT-Thread 的作用

    随着 MCU 硬件性能的提升、外设的增加以及软件功能需求的增加,越来越多项目采用 RTOS 的开发方式。一方面裸机开发方式的软件框架不清晰,对后续扩展功能极其不利;另一方面,由于软件复杂性的增加,裸机开发对工程师的要求越来越严苛,过多使用中断等因素,都会增加系统的不可靠性。

    在这里插入图片描述

    和其他优秀的 RTOS 一样,RT-Thread 的首要目标也是解决这些问题。RT-Thread 内核的主要功能是向下管理所有硬件资源,向上为应用程序提供 API 接口和软件服务,所有任务在内核的管理、同步和调度下有序运行。

    简单来说,使用 RT-Thread 能够带来如下好处:

    • 支持任务并发处理
    • 容易扩展新的功能
    • 破解应用的复杂性
    • 增强代码可移植性
    • 节省软件开发时间

    您可能会说,其他 RTOS 也能提供这些好处呀,为什么你要推荐 RT-Thread?

    因为 RT-Thread 还有许多优点,包括它支持非常多的硬件平台,还拥有及其丰富的组件和软件包(包括文件系统、网络、IoT、AI、传感器等等),提供了便捷的开发环境和 IDE 工具,以及有众多技术文档、参考设计和活跃的开发者社区,这些都能帮助您快速入门和掌握 RT-Thread,开发出优秀的产品。

    当然啦,最重要的是,RT-Thread 是一群扎实做事的中国人写的开源操作系统,帮助您做出好产品的同时还能提高民族自信和国家竞争力。

    1.3 RT-Thread 的特点

    相比其他操作系统,RT-Thread 的主打特性是 “小而美的物联网操作系统”。

    ” 体现在 RT-Thread 的体积小,最小资源占用 1.2KB RAM 和 2.5KB flash。RT-Thread 可伸缩、易裁剪的特性,帮助用户在需要一个适用的操作系统的时候,轻松地进行裁减,适应到需要的场景,不占用过多的资源。

    ” 不单止代码质量和代码风格,还有 RT-Thread 的使用和开发体验,以及增加了小程序、SMP 多核调度、PSA 安全支持等多项实用的新功能,使得 RT-Thread 系统能实现灵活极简的应用开发,能扩展至众多高性能、高安全的应用领域。

    物联网” 则体现在 RT-Thread 针对物联网场景提供的众多组件和软件包,比如 AT组件、WiFi、蓝牙、LoRa、Sensor、AI 等等。以及针对安全和低功耗的优化,还有以 JS 为开发方式的柿饼 UI,都使其非常适用于 IoT 领域。

    1.4 开源的 RT-Thread

    您可能会担忧,RT-Thread 作为一个开源的操作系统,会不会污染企业私有代码?开发过程中会不会有很多坑?

    在这里插入图片描述

    其实不用担心,因为 RT-Thread 是一个“开源、社区化、中立”的系统。遵循 Apache 2.0 开源许可协议,意味着您可以放心地免费在商业产品中使用 RT-Thread 内核和组件,不需要公开私有代码,只需要在产品说明书上提及“基于 RT-Thread 系统”或“Powered by RT-Thread”即可。

    Tips:因为 RT-Thread 软件包平台是开放的,许多软件包都是来自社区开发者,不同软件包的许可协议可能会不一样,所以在商业产品中使用时需要稍加注意。

    同时,RT-Thread 非常注重在嵌入式开源社区的生态建设。经过多年的积累,除了有官方技术支持团队,还有活跃的开源社区和数十万开发者,开发过程中的遇到难题都能寻找官方团队和社区开发者的支持。

    2. RT-Thread 版本

    RT-Thread 针对不同应用场景,目前提供了三个主版本,分别是 RT-Thread 标准版、RT-Thread Nano 和 RT-Thread Smart。

    代码均可在 https://www.rt-thread.org/page/download.html 页面下载。

    2.1 RT-Thread 标准版

    最常用应该是 RT-Thread 标准版(也称为 RT-Thread 全功能版本),它由内核层、组件和服务层、IoT 框架层、文件系统、图形库、设备框架等组成。包含完整的中间件组件,具备低功耗、安全、通信协议支持和云端连接能力,是一个完整的 IoT OS。

    在这里插入图片描述

    可以看到,除了实时内核,RT-Thread 标准版还具备丰富的中间层组件和软件包生态,这也是 RT-Thread 与其他很多 RTOS 的主要区别之一。

    2.2 RT-Thread Nano

    RT-Thread Nano 是一个极简的硬实时内核,其内存资源占用极小,功能包括任务管理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。对于系统资源紧张或是项目功能较为简单的,则可以选择基于 RT-Thread Nano 进行开发。比如家电、消费、医疗、工控领域的 32 位入门级 MCU。

    在这里插入图片描述

    Tips:RT-Thread Nano 已得到 ARM Keil 官方的认可和支持,在 Keil MDK 中以 pack 方式提供,方便用户使用。

    2.3 RT-Thread Smart

    RT-Thread Smart 是一款高性能混合微内核操作系统。其定位在于填补传统 RTOS 和大型操作系统 Linux 之间的空白,在实时性、成本、安全性、启动速度等方面取得最佳的平衡。适用于带 MMU 的中高端应用的芯片,例如 ARM Cortex-A 系列芯片、MIPS 芯片、带 MMU 的 RISC-V 芯片等。广泛应用于安防、车载、军工、消费电子等领域。

    在这里插入图片描述

    RT-Thread Smart 在 RT-Thread 标准版的基础上启用独立、完整的进程方式,同时以混合微内核模式执行。这里“混合”的意思是指在编译时决定整体系统采用什么样的运行模式。

    在这里插入图片描述

    2.4 更多

    除了以上三个主版本,RT-Thread 还有不同的演进版本,包括前几天开发者大会发布的专用于智能穿戴领域的 PersimUI OS(湃心OS),以及应用于智能表计领域的 MoM(Microkernel on MCU),还有一些许可授权的衍生OS。

    在这里插入图片描述

    3. RT-Thread 设计思想

    RT-Thread 有许多巧妙的设计思想,篇幅有限,这里先介绍几个,其他留给您慢慢探索。

    3.1 任务调度

    RT-Thread 支持多任务,允许多个任务同时运行,但并不是真正的同时运行(对于单核的 MCU),而是宏观上的并行,这就需要线程调度器(任务调度器)来完成任务的调度了。

    在这里插入图片描述

    RT-Thread 最大支持 256 级优先级(0~255),数值越小优先级越高。可以根据实际情况选择 8 或 32 级,对于 ARM Cortex-M 系列,通常采用 32 级优先级。

    调度器是操作系统的核心,其主要功能就是实现线程的切换。RT-Thread 通过管理就绪列表,当需要调度时可以直接找出就绪列表中优先级最高的线程,然后执行该线程,时间复杂度为 O(1)。

    /* ready thread list */
    rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
    
    /* get highest ready priority thread */
    highest_priority_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);
    

    同时,RT-Thread 还采用 round-robin 策略确保对具有相同优先级的所有线程进行同等调度。RT-Thread 的每个线程都有时间片参数,如果您希望控制相同优先级的多个线程的单次运行时长,可以分别给它们设置不同的时间片。

    3.2 启动流程

    RT-Thread 系统的初始化在 main() 函数之前,这意味着您不需要操心 RT-Thread 的初始化操作,可以专心编写应用程序。

    RT-Thread 还提供了自动初始化机制,初始化函数只需要在函数定义处通过宏定义的方式进行声明,就会在系统启动过程中自动执行,不需要在应用代码中显示调用,相当优雅。

    针对不同层级,RT-Thread 提供了不同的宏接口:

    初始化顺序宏接口描述
    1INIT_BOARD_EXPORT(fn)非常早期的初始化,此时调度器还未启动
    2INIT_PREV_EXPORT(fn)主要是用于纯软件的初始化、没有太多依赖的函数
    3INIT_DEVICE_EXPORT(fn)外设驱动初始化相关,比如网卡设备
    4INIT_COMPONENT_EXPORT(fn)组件初始化,比如文件系统或者 LWIP
    5INIT_ENV_EXPORT(fn)系统环境初始化,比如挂载文件系统
    6INIT_APP_EXPORT(fn)应用初始化,比如 GUI 应用

    3.3 内核对象

    RT-Thread 内核采用面向对象的设计思想进行设计,系统级的基础设施都是内核对象,比如线程、信号量、互斥量、事件、邮箱、消息队列、定时器、内存池、设备驱动等等。然后通过内核对象管理系统来访问/管理所有内核对象,例如当您创建一个对象时,内核对象管理系统就会将这个对象放到一个叫对象容器的地方。

    在这里插入图片描述

    这样做是为了方便管理内核资源,在后续的开发调试阶段可以很方便地获取各个内核对象的状态,并通过 FinSH 输出调试信息。

    3.4 FinSH 控制台

    FinSH 是 RT-Thread 最早的组件之一,提供了一套类似于 Linux Shell 的操作接口,您可以通过 串口/以太网/USB 等方式与 PC 机进行通信,通过命令行查看系统信息或用于调试。

    在这里插入图片描述

    RT-Thread 默认内置了一些 FinSH 命令,比如 list_threadps 用于查看线程信息,list_sem 用于查看系统信号量信息,free 用于查看系统内存使用情况等等。如果开启 DFS 组件,还可以使用 lscdcp 等命令操作文件系统。

    4. RT-Thread 快速上手

    为了提升开发体验,RT-Thread 为我们提供了几种开发环境,主要包括使用多年的 Env 工具和近年来主推的 RT-Thread Studio 集成开发环境。

    4.1 Env 工具

    Env 是 RT-Thread 推出的开发辅助工具,针对基于 RT-Thread 操作系统的项目工程,提供编译构建环境、图形化系统配置及软件包管理功能。其内置的 menuconfig 提供了简单易用的配置剪裁工具,可对内核、组件和软件包进行自由裁剪,使系统以搭积木的方式进行构建。

    在这里插入图片描述

    4.2 RT-Thread Studio

    RT-Thread Studio 是一个基于 Eclipse 的开发工具软件,主要包括工程创建和管理,代码编辑,SDK管理,RT-Thread配置,构建配置,调试配置,程序下载和调试等功能。

    • 优点:低门槛快速上手,一站式开发,图形化配置,社区版本永久免费。
    • 缺点:目前只支持 Windows 平台,配置、编译、运行速度较慢,支持的硬件平台较少。
    • 下载:https://www.rt-thread.org/page/studio.html

    在这里插入图片描述

    4.3 其他

    还有其他一些开发方式,比如在 Keil MDK 中以 pack 形式添加 RT-Thread 内核。

    5. 如何参与社区贡献

    最后,如果您也想参与社区建设,为 RT-Thread 的生态贡献一份力量,那么您可以结合自身情况选择轻度参与或重度参与。

    5.1 轻度参与

    • 在公司产品、个人项目或比赛中使用 RT-Thread;
    • RT-Thread 社区 中提问或回答问题;
    • GitHub 给 RT-Thread 提 Issue 反馈 Bug;
    • 参与社区活动和 B站 直播;

    5.2 重度参与

    • GitHub 给 RT-Thread 提 PR 修复 Bug 或增加新功能;
    • 制作软件包并提交到 官方软件包索引仓库
    • 领取 任务 并加入 社区工作小组
    • 组建社区兴趣小组一起学习;
    • 在当地组织或参与开发者沙龙;
    • 参与 RT-Thread 开发者能力认证考试;

    还有,别忘了参加 RT-Thread 年度开发者大会!

    6. 有哪些学习资料

    展开全文
  • Exception in thread "main" java.lang.Error: Unresolved compilation problem: Syntax error, insert ";" to complete Statement at cn.com.infosec.test.Rsaa.main(Rsaa.java:157)(线程"主要的"java.lang.e...

    怎样解决报错:

    Exception in thread "main" java.lang.Error: Unresolved compilation problem:

    Syntax error, insert ";" to complete Statement at cn.com.infosec.test.Rsaa.main(Rsaa.java:157)(线程"主要的"java.lang.error:未解决的编译问题异常:语法错误,插入"(2);",在cn.com.infosec.test.rsaa.main(rsaa.java:157)上完成语句)

    一开始是:

    然后我选中红波浪线删除就好了,如下第30行已经不报错了。

    明显的报错还容易解决,但隐性的就不好解决了,如下:

    把鼠标放在红叉的地方显示:Syntax error, insert ";" to complete Statement(语法错误,插入“;”以完成语句)

    执行代码后就报

    Exception in thread "main" java.lang.Error: Unresolved compilation problem:

    Syntax error, insert ";" to complete Statement at cn.com.infosec.test.Rsaa.main(Rsaa.java:157)(线程"主要的"java.lang.error:未解决的编译问题异常:语法错误,插入"(2);",在cn.com.infosec.test.rsaa.main(rsaa.java:157)上完成语句)错误。

    我百度了一下,他们说是由于jdk版本的问题,或者新建一个类,把代码复制过去就好了,但我改了还是不行。

    摸索挺久后,才发现了解决方法:

     如上图,将上图中的空白选中,并删除,就好了。

     总结:由于,这是在网上复制别人的代码,所以有些复制下来的代码会存在特殊字符,需要把他们都删除。实在找不到,只好老老实实自己敲一遍代码啦。总之,报这种错误有很多原因,就看你的原因是那种了。

    展开全文
  • 我们进行程序开发的时候,肯定避免不了要处理并发的情况。 一般并发的手段有采用多进程和多线程。 但线程比进程更轻量化,系统开销一般也更低,所以大家更倾向于用多线程的方式处理并发的情况。...thread...
  • Android中线程(Thread)的创建及内存分配过程分析 本文详细分析Android中,线程的创建过程以及线程创建时,内存的分配。 Java层Thread的分析 我们想要创建一个线程,通常都是使用Thread类,创建一个Thread的实例...
  • RT-Thread学习笔记——移植RT-Thread到STM32

    万次阅读 多人点赞 2019-01-22 11:08:27
    从本文开始,记录自己的RT-Thread学习笔记,基于STM32L475VET6讲解,相关开发板用RTT&amp;正点原子的潘多拉IoT Board开发板。本文先从Nano开始学起,个人觉得对于初学者,还是先学会Nano的移植,把内核部分向学...
  • RT-Thread Smart 上手指南

    万次阅读 2020-11-26 18:55:04
    RT-Thread Smart(简称rt-smart)是基于RT-Thread操作系统衍生的新分支,面向带MMU,中高端应用的芯片,例如ARM Cortex-A系列芯片,MIPS芯片,带...
  • Thread 类部分常用方法详解

    千次阅读 2020-09-29 23:25:21
    currentThread() 方法用来返回代码段正在被哪个线程调用,它是 Thread 类提供的一个 native 方法,返回一个 Thread 类的实例对象,源码如下: public static native Thread currentThread(); 废话就不多说了,直接...
  • Java Thread 实现方式

    千次阅读 2018-05-09 08:45:45
    关于Thread有一个比较有趣的面试题。当你new 一个Thread的时候,直接调用它的run()方法,run()会执行在哪个线程? 答案是调用run()的线程,因为只有在调用start()之后,Java才会创建一个新的线程,然后新的线程再...
  • thread dump分析

    千次阅读 2018-07-30 19:55:05
    一、thread dump信息获取 1、发送信号 * In Unix, use "kill -3 &lt;pid&gt;" where pid is the Process ID of the JVM.(kill 信号列表) * In Windows, press CTRL+BREAK on the window where ...
  • 彻底理解Runnable和Thread的区别

    万次阅读 多人点赞 2019-07-30 09:45:42
      在实际工作中,我们很可能习惯性地选择Runnable或Thread之一直接使用,根本没在意二者的区别,但在面试中很多自以为是的菜货面试官会经常而且非常严肃的问出:请你解释下Runnable或Thread的区别?尤其是新手就...
  • Java Thread类源码详解

    千次阅读 2018-08-23 14:51:18
    Java所有多线程的实现,均通过封装Thread类实现,所以深入Thread类,对深入理解java多线程很有必要 构造函数: Thread的构造函数,采用缺省的方式实现: //传入Runnable接口实现 Thread...
  • RT-Thread Studio快速配置GPIO进行点灯

    千次阅读 2021-06-03 15:59:30
    本章通过RT-Thread Studio配置AB32VG1片上外设GPIO的引脚,控制RGB彩灯进行简单的颜色变换
  • 线程(Thread)(代码)

    千次阅读 2020-05-14 11:59:01
    在了解线程之前,我们先看看线程与进程的区别 进程:是正在运行的程序 是系统进行资源分配和调用的独立单位 每一个进程都有它自己的内存空间和系统资源 ...线程:是进程中的单个顺序控制流,是...继承Thread类 实.
  • 我移植成功的工程已经上传至我的资源,有需要的可以下载一下:... 一:简介RT-Thread 1.RT-Thread 简介 作为一名 RTOS 的初学者,也许你对 RT-Thread 还比较陌生。然而,随着你的深入接...
  • 当初跟踪Camera的代码中的时候一直追到了HAL层,而在Framework中的代码看见了若干个Thread。它们普遍的特点就是有一个threadLoop方法。按照字面的意思应该是这个线程能够循环处理数据。对应我想到到了java上层中的...
  • C++11多线程thread参数传递问题

    万次阅读 多人点赞 2018-12-31 12:01:51
    thread类的构造函数 join函数 detach函数 thread中参数传递 类对象作为参数 类中函数作为参数 参考书籍 写在前面 多线程在很多地方都是必须要掌握的方法,这里先说一下,thread对象的参数传递问题 thread类...
  • RTThread(一) - 概念及简介

    千次阅读 多人点赞 2020-11-09 21:34:20
    文章目录前置说明RTThread框架线程管理及调度器线程间通信管理时钟管理内存分布内存管理动态内存堆管理静态内存池管理RTT启动过程自动初始化机制内核对象管理架构内核配置&剪裁 前置说明 一般单片机一般只有一个...
  • [超级链接:Java并发学习系列-绪论] 本章主要对Java中线程的状态转换进行学习。 1.前言 ...thread.join():在当前线程中加入指定线程,使得这个指定线程等待当前线程,并在当前线程结束前结束。 t...
  • C++11中头文件thread的使用

    万次阅读 2017-06-17 22:56:04
    thread>头文件,此头文件主要声明了std::thread线程类。C++11的标准类std::thread对线程进行了封装。std::thread代表了一个线程对象。应用C++11中的std::thread便于多线程程序的移值。 <thread>是C++标准...
  • 通过阅读源码或者官方的API,可以知道 Thread#stop() 方法已经被废弃了。 大致意思 这种方法本质上是不安全的。 使用Thread.stop停止线程会导致它解锁所有已锁定的监视 如果先前由这些监视器保护的任何对象处于...
  • 华大单片机移植RTThread操作系统

    千次阅读 多人点赞 2020-09-27 16:26:02
    华大单片机移植RTThread-国产操作系统 文章目录华大单片机移植RTThread-国产操作系统1.华大单片机型号选择2.RTThread源码下载2.1 .资料说明2.3.源码下载3.移植过程3.1.新建华大单片机最小系统工程模板,这里不展开...
  • C#中的Thread

    万次阅读 2018-07-28 12:52:19
    1.通过Thread对象开启线程 1.1函数调用  首先用new申请Thread对象,然后对象调用Start()方法启用线程。  Thread.CurrentThread.ManagedThreadId获取当前线程的ID,便于管理。 class Program { static void ...
  • 图 3-1 为 RT-Thread 内核架构图,内核处于硬件层 之上,内核部分包括内核库、实时内核实现。 RT-Thread 内核及底层结构  内核库是为了保证内核能够独立运行的一套小型的类似 C 库 [1] 的函数实现子集。这...
  • 理解Thread.interrupt()的含义

    万次阅读 多人点赞 2018-10-14 11:51:56
    其实Thread.interrupt()并不会中断线程的运行,它的作用仅仅是为线程设定一个状态而已,即标明线程是中断状态,这样线程的调度机制或我们的代码逻辑就可以通过判断这个状态做一些处理,比如sleep()方法会抛出异常,...
  • RT-Thread 快速入门实例教程 一般嵌入式操作系统因为它的特殊性,往往和硬件平台密切相关连,具体的嵌入式操作系统往往只能在特定的硬件上运行。对于刚接触 RT-Thread 操作系统的读者并不容易马上就获得一个和 RT-...
  • ThreadGroup

    万次阅读 2018-10-17 10:17:23
    本文不会对ThreadGroup如何使用进行分析,而是通过解析ThreadGroup的树形结构实现,以便更好的理解ThreadGroup的设计意义
  • RT-Thread操作系统

    万次阅读 2018-09-26 20:40:17
    一、RT-Thread与UCOS的简单比较 任务或线程调度 RT-Thread可选优先级抢占式调度,256/32/8个优先级,线程数不限。相同优先级线程时间片轮转调度。支持动态创建/销毁线程。 Ucos优先级抢占式调度。不允许相同优先级...
  • JAVA线程之Thread类详解

    万次阅读 多人点赞 2018-05-30 16:22:23
    Thread类用于操作线程,是所以涉及到线程操作(如并发)的基础。本文将通过源码对Thread类的功能作用进行分析。 一、属性 /* Make sure registerNatives is the first thing <clinit> does. */ private...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,936,092
精华内容 774,436
关键字:

thread