⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread.c

📁 这是嵌入式Linux操作系统下多线程的编程的源程序
💻 C
字号:
/*!***************************************************************************************************** * *  File : thread.c * *  Purpose : implement a thread package with makecontext()/setcontext() and setitimer() * *  OS : Tru64 Unix V4.0F * *  Designer : Hao Chen  * *  Authour : Hao Chen * *----------------------------------------------------------------------------------------------------- * * 					Appended Notice * *  1. 2003/12/15 *     1. can not use setitimer()/alarm(). * ------------------------------------------------------------------------------------------------------ * *   					Revistion History * *  0.2  2003/12/17 Hao Chen * *	 1.   add a field( a_cThreadState) in "struct context" . the field represent the state of current *	    running thread. * * 	 2.   fix a serios bug. The bug is that : "the two threads in version 0.1 can switch only once" . * 	      If the thread is swith by other thread, it should run normally instead of setcontext(). *	       *	      in order to solve the problem, I add a state in "struct context". when the timer_hdl() * 	    arrange other thread to run, it will set the thread's state is "RUNNING". after the context *	    of the target thread is switched and the target thread get the control, it will first check *	    it's state. if the state is RUNNIG, it will execute without setcontext(). * * *  0.1  2003/12/15 Hao Chen * * 	 Initial version. can not run correctly * ******************************************************************************************************* */#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <ucontext.h>#define CONTEXT_ARRAY_LEN 	4#define TIMER__MICROSECOND  	100      /*! internal timer is 100 microsecond  */#define TIMER__SECOND		0   	 /*! internal timer is 3 second  */#define TIMER__SIGNAL 		14	 /*! timer signal */#define STACK_SIZE 		8192	 /*! new thread's size */#define THREAD__READY_STATE	1	 /*! not running, but it will be run */#define THREAD__RUNNING_STATE	2	 /*! is running */struct context{    ucontext_t  a_stContext[ CONTEXT_ARRAY_LEN ];    int		a_iUsedFlg[ CONTEXT_ARRAY_LEN ];       /*! 1 : used; 0 : unused */    char	a_cThreadState[ CONTEXT_ARRAY_LEN ];   /*! current thead state */};struct context g_stContext;int    g_iCurrentRunIdx;int    g_iContextNumber ;int iTP_Init( void);int iTP_FindFreeSlot( void);void iTP_ClearSlot( int idx   );int TP_create( int *thread_id, void (*func)( void *), void *arg	);void iTP_TimerHdl( int signal_num  );void TP_exit( void);/*!********************************************************************** * *   Purpose : init global variable * *   Return :  0 : successful * 	       <0 : Failed . * *   Failed Reason : -1 : failed to sigaction(). *		     -2 : failed to setitimer(). * ************************************************************************ */#define __FUNC__  "iTP_Init"int iTP_Init( void){    int 		iRetSts;    struct sigaction 	stSigAction;    struct itimerval	stTimer;    /*!----------------------------------------     *!  init variable      *!----------------------------------------     */    memset( &g_stContext, 0, sizeof( g_stContext));    memset( &stSigAction, 0, sizeof( stSigAction));    /*!------------------------------------------     *!  we can get here once and only once.     *!  then we should give us a a context_space.     *!      *!  we should register ourself.     *!------------------------------------------     */     g_iCurrentRunIdx = 0;     g_stContext.a_iUsedFlg[ g_iCurrentRunIdx ] = 1;     g_iContextNumber = 1;    /*!----------------------------------------     *!  build signal action     *!----------------------------------------     */    stSigAction.sa_handler = iTP_TimerHdl;    sigemptyset( &stSigAction.sa_mask);    if( sigaction( TIMER__SIGNAL, &stSigAction, NULL))   	return -1;    /*!----------------------------------------     *!  create new timer     *!----------------------------------------     */    stTimer.it_interval.tv_sec = TIMER__SECOND;    stTimer.it_interval.tv_usec = TIMER__MICROSECOND;    stTimer.it_value.tv_sec = TIMER__SECOND;    stTimer.it_value.tv_usec = TIMER__MICROSECOND;    if( setitimer( ITIMER_REAL, &stTimer, NULL))	return -2;}/*!********************************************************************** * *   Purpose : find an unused slot *  *   Return : >=0 : find . *  	      -1  : find nothing. * ************************************************************************ */#define __FUNC__  "iTP_FindFreeSlot"int iTP_FindFreeSlot( void){    unsigned int i;    for( i = 0; i < CONTEXT_ARRAY_LEN; i++)    {	if( g_stContext.a_iUsedFlg[ i ] == 0)	{	    g_stContext.a_iUsedFlg[ i ] = 1;	    break;	}    }    return ( i >= 0) ? i : -1;}/*!********************************************************************** * *   Purpose : clear a slot *  *   Return :  None. * ************************************************************************ */#define __FUNC__  "iTP_ClearSlot"void iTP_ClearSlot( int idx   /*! i : index in context_array */		  ){    if( idx >= 0 && idx < CONTEXT_ARRAY_LEN) 	g_stContext.a_iUsedFlg[ idx ] = 0;}/*!********************************************************************** * *  Purpose : create a new thread with appointed fucntion pointer * *  Return : 0 : successful. *	     <0 : failed . * *  Fail Reason : -1 : the argument func is NULL. *		  -2 : the context_array is full. *		  -3 : can not malloc() memory. *		  -4 : internal error : we can not init signal handler. * ************************************************************************ */#define __FUNC__  "TP_create"int TP_create( int *thread_id,  		/*! o : thread id */ 	       void (*func)( void *),		/*! i : user function */	       void *arg			/*! i : argument */	     ){    static int iHaveInitFlg = 0;  /*! 1 : have called TP_init(); 0 : not called */    int iSlotIdx;       /*!--------------------------------     *! make sure that we have inited.     *!--------------------------------     */    if( iHaveInitFlg == 0)    {	if( iTP_Init()) return -4;	iHaveInitFlg = 1;    }     /*!--------------------------------     *!  validate the user argument     *!--------------------------------     */    if( func == NULL) return -1;    /*!--------------------------------     *!  find a free conext slot     *!--------------------------------     */    iSlotIdx = iTP_FindFreeSlot();    if( iSlotIdx == -1) return -2;    /*!--------------------------------     *!  make a next context     *!--------------------------------     */    g_stContext.a_stContext[ iSlotIdx].uc_link = NULL;    g_stContext.a_stContext[ iSlotIdx].uc_stack.ss_sp = ( void *) malloc( STACK_SIZE);    g_stContext.a_stContext[ iSlotIdx].uc_stack.ss_size = STACK_SIZE;    g_stContext.a_stContext[ iSlotIdx].uc_stack.ss_flags = 0;     if( !g_stContext.a_stContext[ iSlotIdx].uc_stack.ss_sp )    {	iTP_ClearSlot( iSlotIdx);	return -3;    }    /*!--------------------------------     *!  make the next context.     *!--------------------------------     */    makecontext( &g_stContext.a_stContext[ iSlotIdx],		 func,		 1,		 arg);    ++g_iContextNumber;    return 0;}/*!************************************************************** * *   Purpose : This is our dispatcher since it is a signal_handler. * * *!************************************************************** */#define __FUNC__  "iTP_TimerHdl"void iTP_TimerHdl( int signal_num  /*! i: signal number */		 ){    int 		i, iOldRunIdx;    int 		iRetSts;    struct sigaction 	stSigAction;    /*!----------------------------------------     *!  rebuild signal action      *!----------------------------------------     */    memset( &stSigAction, 0, sizeof( stSigAction));    stSigAction.sa_handler = iTP_TimerHdl;    sigemptyset( &stSigAction.sa_mask);    iRetSts = sigaction( TIMER__SIGNAL, &stSigAction, NULL);       if( iRetSts == -1)    {	perror( "sigaction() failed in iTP_TimerHdl because :");	abort();    }    /*!------------------------------------------     *!  if there is zero or one context, we can not switch .     *!------------------------------------------     */    if( g_iContextNumber <= 1) return ;        /*!------------------------------------------     *!  find next runnable conext     *!------------------------------------------     */    i = ( g_iCurrentRunIdx + 1) % CONTEXT_ARRAY_LEN;    while( i != g_iCurrentRunIdx)    {	if( g_stContext.a_iUsedFlg[ i ] == 1) break;	i = ( i + 1) % CONTEXT_ARRAY_LEN;;    }    if( i == g_iCurrentRunIdx) return;    /*!------------------------------------------     *!  we should switch now.     *!  1. save current context     *!  2. set the older context now.     *!------------------------------------------     */    g_stContext.a_cThreadState[ g_iCurrentRunIdx ] = THREAD__READY_STATE;    getcontext( &g_stContext.a_stContext[ g_iCurrentRunIdx ]);        /*!--------------------------------------------------------------------     *!  NOTE:     *!	    we can get here from two ways :      *!	    1. from above codes line by line.     *!	    2. "swithed" by other "thread"     *!--------------------------------------------------------------------     */    if( g_stContext.a_cThreadState[ g_iCurrentRunIdx ] == THREAD__READY_STATE)    {	g_iCurrentRunIdx = i;	g_stContext.a_cThreadState[ g_iCurrentRunIdx ] = THREAD__RUNNING_STATE;	setcontext( &g_stContext.a_stContext[ g_iCurrentRunIdx]);    }}/*!************************************************************** * *   Purpose : exit the thread now * *!************************************************************** */#define __FUNC__  "iTP_TimerHdl"void TP_exit( void){    sigset_t iNewSigSet, iOldSigSet;    /*!---------------------------------------------------------------     *!  tell the OS not to send TIMER__SIGNAL when we exit a thread for atomic reason.      *!---------------------------------------------------------------     */    sigemptyset( &iNewSigSet);    sigaddset( TIMER__SIGNAL, &iNewSigSet);    sigpromask( SIG_BLOCK, &iNewSigSet, &iOldSigSet);    iTP_ClearSlot( g_iCurrentRunIdx);    --g_iContextNumber;    /*!---------------------------------------------------------------     *!  resume the signal set mask.      *!---------------------------------------------------------------     */    sigpromask( SIG_SETMASK, &iOldSigSet);}void gg( void *arg){    int i = 0;    while(1)     {	printf( "gg \t\t\t\t%d\n",  ++i);	if( i == 700) TP_exit();    }}void ff( void *arg){    int i = 0;    while(1)     {	printf( "ff %d\n",  ++i);    }}void main( void){    int iThreadId;    int j = 0;    TP_create( &iThreadId, ff, NULL);    TP_create( &iThreadId, gg, NULL);     while(1)     {	printf( "\t\tmain %d\n", ++j);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -