程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> rt-thread的IPC機制之信號量源碼分析

rt-thread的IPC機制之信號量源碼分析

編輯:C++入門知識

rt-thread操作系統的IPC(Inter-Process Communication,進程間通信)包含有信號量,互斥鎖,事件,郵箱,消息隊列. 本文主要針對信號量. 1 信號量控制塊 [cpp]   /**   * Semaphore structure   */   struct rt_semaphore   {       struct rt_ipc_object parent;                        /**< inherit from ipc_object *///派生自IPC對象          rt_uint16_t          value;                         /**< value of semaphore. *///信號量計數器   };   typedef struct rt_semaphore *rt_sem_t;     value為信號計數器,parent為一rt_ipc_object即IPC對象,其定義如下: [cpp]   /**   * Base structure of IPC object   */   struct rt_ipc_object   {       struct rt_object parent;                            /**< inherit from rt_object *///可知其派生自內核對象          rt_list_t        suspend_thread;                    /**< threads pended on this resource *///線程掛起鏈表   };     從rt_ipc_object的定義結構可知其派生自rt_object結構,即內核對象的定義(參考http://blog.csdn.net/flydream0/article/details/8568463),另外,它不包含一鏈表,用來保存因此信號量而掛起的線程. 2 信號量的創建與初始化 2.1 初始化 [cpp]   /**   * This function will initialize a semaphore and put it under control of   * resource management.   *   * @param sem the semaphore object   * @param name the name of semaphore   * @param value the init value of semaphore   * @param flag the flag of semaphore   *   * @return the operation status, RT_EOK on successful   */   rt_err_t rt_sem_init(rt_sem_t    sem,                        const char *name,                        rt_uint32_t value,                        rt_uint8_t  flag)   {       RT_ASSERT(sem != RT_NULL);          /* init object */       rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);//初始化信號量的內核對象          /* init ipc object */       rt_ipc_object_init(&(sem->parent));//初始化信號量的IPC對象          /* set init value */       sem->value = value;//設置信號量計數器的值          /* set parent */       sem->parent.parent.flag = flag;//設置信號量的內核對象的標志          return RT_EOK;   }     其中rt_object_init已在之前介紹rt-thread的內核對象中相關文章中已有介紹(參見:http://blog.csdn.net/flydream0/article/details/8568463),rt_ipc_object_init函數見如下: [cpp]  /**   * @addtogroup IPC   */      /*@{*/      /**   * This function will initialize an IPC object   *   * @param ipc the IPC object   *   * @return the operation status, RT_EOK on successful   */   rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc)   {       /* init ipc object */       rt_list_init(&(ipc->suspend_thread));//初始化線程掛起鏈表          return RT_EOK;   }     2.2 創建信號量 [cpp]  /**   * This function will create a semaphore from system resource   *   * @param name the name of semaphore   * @param value the init value of semaphore   * @param flag the flag of semaphore   *   * @return the created semaphore, RT_NULL on error happen   *   * @see rt_sem_init   */   rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)   {       rt_sem_t sem;          RT_DEBUG_NOT_IN_INTERRUPT;//確保此函數不是在中斷中使用          /* allocate object */       sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name);//動態分配內核對象       if (sem == RT_NULL)           return sem;          /* init ipc object */       rt_ipc_object_init(&(sem->parent));//初始化信號量的IPC對象          /* set init value */       sem->value = value;//初始化信號量的計數器值          /* set parent */       sem->parent.parent.flag = flag;//設置信號量的內核對象的標志          return sem;   }     3 脫離及刪除信號量 3.1 脫離信號量 [cpp]  /**   * This function will detach a semaphore from resource management   *   * @param sem the semaphore object   *   * @return the operation status, RT_EOK on successful   *   * @see rt_sem_delete   */   rt_err_t rt_sem_detach(rt_sem_t sem)   {       RT_ASSERT(sem != RT_NULL);          /* wakeup all suspend threads */       rt_ipc_list_resume_all(&(sem->parent.suspend_thread));//喚醒所有信號量內掛起的線程          /* detach semaphore object */       rt_object_detach(&(sem->parent.parent));//脫離信號量的內核對象          return RT_EOK;   }     其中rt_ipc_list_resume_all函數如下: [cpp]   /**   * This function will resume all suspended threads in a list, including   * suspend list of IPC object and private list of mailbox etc.   *   * @param list of the threads to resume   *   * @return the operation status, RT_EOK on successful   */   rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)   {       struct rt_thread *thread;       register rt_ubase_t temp;          /* wakeup all suspend threads */       while (!rt_list_isempty(list))//遍歷線程掛起鏈表       {           /* disable interrupt */           temp = rt_hw_interrupt_disable();//關中斷              /* get next suspend thread */           thread = rt_list_entry(list->next, struct rt_thread, tlist);//獲得線程           /* set error code to RT_ERROR */           thread->error = -RT_ERROR;//設置線程的錯誤碼為-RT_ERROR              /*           * resume thread           * In rt_thread_resume function, it will remove current thread from           * suspend list           */           rt_thread_resume(thread);//喚醒此線程              /* enable interrupt */           rt_hw_interrupt_enable(temp);//開中斷       }          return RT_EOK;   }     3.2 刪除線程 [cpp]  /**   * This function will delete a semaphore object and release the memory   *   * @param sem the semaphore object   *   * @return the error code   *   * @see rt_sem_detach   */   rt_err_t rt_sem_delete(rt_sem_t sem)   {       RT_DEBUG_NOT_IN_INTERRUPT;//確保此函數不是在中斷中使用          RT_ASSERT(sem != RT_NULL);          /* wakeup all suspend threads */       rt_ipc_list_resume_all(&(sem->parent.suspend_thread));//喚醒所有掛起的線程          /* delete semaphore object */       rt_object_delete(&(sem->parent.parent));//刪除信號量內核對象          return RT_EOK;   }     4 獲取信號量 4.1 等待信號量 [cpp]   /**   * This function will take a semaphore, if the semaphore is unavailable, the   * thread shall wait for a specified time.   *   * @param sem the semaphore object   * @param time the waiting time   *   * @return the error code   */   rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)   {       register rt_base_t temp;       struct rt_thread *thread;          RT_ASSERT(sem != RT_NULL);          RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent)));          /* disable interrupt */       temp = rt_hw_interrupt_disable();//關中斷          RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d\n",                                   rt_thread_self()->name,                                   ((struct rt_object *)sem)->name,                                   sem->value));          if (sem->value > 0)//如果此信號量的計數器的值大於0,說明有信號,則應該立即返回       {           /* semaphore is available */           sem->value --;//則將信號量的計數器的值減1              /* enable interrupt */           rt_hw_interrupt_enable(temp);//開中斷       }       else//如果此信號量的計數器的值小於或等於0,說明此時還未有信號       {           /* no waiting, return with timeout */           if (time == 0)//如果等待時間參數為0,則立即返回超時錯誤           {               rt_hw_interrupt_enable(temp);//開中斷                  return -RT_ETIMEOUT;//返回超時錯誤           }           else//等待信號           {               /* current context checking */               RT_DEBUG_NOT_IN_INTERRUPT;//確保此時不在中斷中使用                  /* semaphore is unavailable, push to suspend list */               /* get current thread */               thread = rt_thread_self();//獲取當前正在運行的線程                  /* reset thread error number */               thread->error = RT_EOK;//設置當前線程的錯誤代碼為RT_EOK,需要注意這裡                  RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n",                                           thread->name));                  /* suspend thread */               rt_ipc_list_suspend(&(sem->parent.suspend_thread),//掛起當前線程到信號量中的斷起線程鏈表                                   thread,                                   sem->parent.parent.flag);                  /* has waiting time, start thread timer */               if (time > 0)//如果時間參數大於0               {                   RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",                                               thread->name));                      /* reset the timeout of thread timer and start it */                   rt_timer_control(&(thread->thread_timer),//設置定時器                                    RT_TIMER_CTRL_SET_TIME,                                    &time);                   rt_timer_start(&(thread->thread_timer));//啟動定時器開始計時               }                  /* enable interrupt */               rt_hw_interrupt_enable(temp);//開中斷                  /* do schedule */               rt_schedule();//當前線程已掛起,需要重新調試線程               //rt_schedule之後再執行到這裡,只有兩種可能,一是當前線程被掛起後時間已到達,此時,定時器的超時回調處理函數會將此線程的err值設為-RT_ETIMEOU,見thread.c源文件中的rt_thread_timeout函數;另一種情況是,有信號量到來,當前線程被rt_sem_release函數喚醒,此時,此線程的err值將一直保持原樣不變,因此可以下面可能通過判斷線程的err值來判斷當前線程是否已被接收到信號量               if (thread->error != RT_EOK)//如果當前線程的錯誤代碼不為RT_EOK,則返回,否則一直阻塞到等待到有信號到達或超時               {                   return thread->error;               }           }       }          RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent)));          return RT_EOK;   }     4.2 獲取無等待信號量 [cpp]   /**   * This function will try to take a semaphore and immediately return   *   * @param sem the semaphore object   *   * @return the error code   */   rt_err_t rt_sem_trytake(rt_sem_t sem)   {       return rt_sem_take(sem, 0);   }     由此可見,rt_sem_trytake只是rt_sem_take函數的一種特例,時間參數為0而已. 5 釋放信號量 [cpp]   /**   * This function will release a semaphore, if there are threads suspended on   * semaphore, it will be waked up.   *   * @param sem the semaphore object   *   * @return the error code   */   rt_err_t rt_sem_release(rt_sem_t sem)   {       register rt_base_t temp;       register rt_bool_t need_schedule;          RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent)));          need_schedule = RT_FALSE;//默認情況下設置不需要重新調度標記          /* disable interrupt */       temp = rt_hw_interrupt_disable();//關中斷          RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n",                                   rt_thread_self()->name,                                   ((struct rt_object *)sem)->name,                                   sem->value));          if (!rt_list_isempty(&sem->parent.suspend_thread))//掛起線程不為空       {           /* resume the suspended thread */           rt_ipc_list_resume(&(sem->parent.suspend_thread));//喚醒第一個掛起的線程           need_schedule = RT_TRUE;//需要重新調度       }       else           sem->value ++; /* increase value *///信號量計數器加1          /* enable interrupt */       rt_hw_interrupt_enable(temp);//開中斷          /* resume a thread, re-schedule */       if (need_schedule == RT_TRUE)//如果需要重新調度線程,則重新調度           rt_schedule();          return RT_EOK;   }     其中函數rt_ipc_list_resume只會喚醒信號量中第一個掛起的線程,其源碼如下: [cpp]   /**   * This function will resume the first thread in the list of a IPC object:   * - remove the thread from suspend queue of IPC object   * - put the thread into system ready queue   *   * @param list the thread list   *   * @return the operation status, RT_EOK on successful   */   rt_inline rt_err_t rt_ipc_list_resume(rt_list_t *list)   {       struct rt_thread *thread;          /* get thread entry */       thread = rt_list_entry(list->next, struct rt_thread, tlist);//獲取線程          RT_DEBUG_LOG(RT_DEBUG_IPC, ("resume thread:%s\n", thread->name));          /* resume it */       rt_thread_resume(thread);//喚醒此線程          return RT_EOK;   }   6 信號量控制 [cpp]   /**   * This function can get or set some extra attributions of a semaphore object.   *   * @param sem the semaphore object   * @param cmd the execution command   * @param arg the execution argument   *   * @return the error code   */   rt_err_t rt_sem_control(rt_sem_t sem, rt_uint8_t cmd, void *arg)   {       rt_ubase_t level;       RT_ASSERT(sem != RT_NULL);          if (cmd == RT_IPC_CMD_RESET)//重置信號量的計數器值       {           rt_uint32_t value;              /* get value */           value = (rt_uint32_t)arg;           /* disable interrupt */           level = rt_hw_interrupt_disable();//關中斷              /* resume all waiting thread */   www.2cto.com         rt_ipc_list_resume_all(&sem->parent.suspend_thread);//喚醒信號量上所有掛起的線程              /* set new value */           sem->value = (rt_uint16_t)value;//設置信號時的計數器值              /* enable interrupt */           rt_hw_interrupt_enable(level);//開中斷              rt_schedule();//立即重新調試              return RT_EOK;       }          return -RT_ERROR;   }    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved