源码


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>

typedef struct tag_DLIST_NODE
{
    struct tag_DLIST_NODE *prev;
    struct tag_DLIST_NODE *next;
} DLIST_NODE;

typedef DLIST_NODE DLIST_HEAD;

#define dlist_init(e) \
    (e)->prev = (e)->next = (e)

#define dlist_del(e) \
{(e)->prev->next = (e)->next; (e)->next->prev = (e)->prev; }

#define dlist_add(e, p) \
{ (e)->prev = (p); (e)->next = (p)->next; (p)->next = (e); (e)->next->prev = (e); }

#define dlist_insert(e, n) \
{ (e)->prev = (n)->prev; (e)->next = (n); (n)->prev->next = (e); (n)->prev = (e); }

#define dlist_isempty(e) \
    ( ( (e)->prev == (e) && (e)->next == (e) ) ? 1 : 0 )

#define dlist_entity(type, m, e) \
    ( (type *)((unsigned long)(e) - (unsigned long)&((type *)0)->m) )

#define dlist_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); \
         pos = pos->next)

#define dlist_for_each_safe(pos, n, head) \
    for (pos = (head)->next, n = pos->next; pos != (head); \
         pos = n, n = pos->next)

#define ELEVATOR_NUM 4
#define ELEVATOR_FLOOR_NUM 10

typedef struct person_s
{
    DLIST_NODE node;
    int id;
    int floor;
    int tid;
    int uptime;
    int downtime;
}person_t;
typedef struct person_queue_s
{
    DLIST_HEAD head;
    int personCount;
    pthread_mutex_t stMutex;
}person_queue_t;
typedef struct elevator_s
{
    DLIST_HEAD head;
    int id;
    int floor;
    int personCount;
    int upCount;
    int downCount;
    int stime;
}elevator_t;
typedef struct time_node_s
{
    DLIST_NODE node;
    void *(*pFunc)(int);
    int expire;
    int passed;
}time_node_t;

typedef struct time_queue_s
{
    DLIST_HEAD head;
    int timeCount;
    int runPerSeconds;
}time_queue_t;
static int id = 1;
person_queue_t  *gstPersonQueue = NULL;

void time_proc(int expire)
{
    person_t *person = NULL;

    if(!gstPersonQueue)
    {
        return;
    }
    person = malloc(sizeof(person_t));
    if(!person)
    {
        return;
    }
    person ->floor = expire;
    person->id =  id++;

    //printf("[ID :%d %d]\n",person->id,expire);
    pthread_mutex_lock(&gstPersonQueue->stMutex);
    dlist_insert(&person->node,&gstPersonQueue->head);
    gstPersonQueue->personCount++;
    pthread_mutex_unlock(&gstPersonQueue->stMutex);
}

int add_timer(time_queue_t *pstQueue, void *pFunc, int ulTime)
{
    time_node_t *pstNode = NULL;
    pstNode = (time_node_t *)malloc(sizeof(time_node_t));
    if(!pstNode)
    {
        return -1;
    }
    memset(pstNode,0,sizeof(time_node_t));

    pstNode->pFunc = pFunc;
    pstNode->expire = ulTime;
    pstNode->passed = 0;

    dlist_insert(&pstNode->node,&pstQueue->head);
    pstQueue->timeCount += 1;
    return 0;
}

void *start_timer(void *queue)
{
#if 0
    int i = 1;
#endif
    time_queue_t *pstQueue = NULL;
    time_node_t *pstNode = NULL;
    DLIST_NODE *pos = NULL ,*next = NULL;

    pstQueue = (time_queue_t *)queue;
    if(!pstQueue)
    {
        return NULL;
    }

    while(1)
    {
        usleep(1000000*pstQueue->runPerSeconds);
        dlist_for_each_safe(pos,next,&pstQueue->head)
        {
            pstNode = dlist_entity(time_node_t,node,pos);
            if((pstNode->passed + pstQueue->runPerSeconds) > pstNode->expire)
            {
                pstNode->pFunc(pstNode->expire);
                pstNode->passed = 0;
            }
            pstNode->passed++;
        }
#if 0        
        if(i++ == 11)
        {
            break;
        }
#endif
    }
    return NULL;
}

void *elevator_run(void *data)
{
    int upnum = 0;
    int downnum = 0;
    struct tm *p;
    time_t time;
    int up = 0;
    person_t *person = NULL;
    DLIST_NODE *pos = NULL, *next = NULL;
    elevator_t *pstElevator=NULL;
    pstElevator = (elevator_t *)(data);
    printf("[ELEVATOR:%d] running!\n",pstElevator->id);
    while(1)
    {
        pstElevator->stime++;
        upnum = 0;
        downnum = 0;
        pos = NULL;
        next = NULL;
        person = NULL;
        if(!gstPersonQueue)
        {
            continue;
        }
        /*up*/
        if(pstElevator->floor == 1)
        {
                            upnum = 0;
            pthread_mutex_lock(&gstPersonQueue->stMutex);
            if(gstPersonQueue->personCount)
            {
                /*up*/
                //printf("UP-IDS");
                dlist_for_each_safe(pos,next,&gstPersonQueue->head)
                {
                    person = dlist_entity(person_t,node,pos);
                    dlist_del(pos);
                    dlist_insert(&person->node,&pstElevator->head);
                    gstPersonQueue->personCount--;
                    /*update elevator*/
                    pstElevator->upCount++;
                    pstElevator->personCount++;
                    upnum++;
                    //printf(" %d ",person->id);
                }
                //printf("\n");
                time = (time_t)pstElevator->stime;
                p=localtime(&time);
                //printf("[Time%d:%d:%d][Elevator%d floor 1 up %d persons]\n",p->tm_hour,p->tm_min,p->tm_sec,pstElevator->id,upnum);
                printf("[时间%d:%d:%d][电梯%d在1层上了%d个人]\n",p->tm_hour,p->tm_min,p->tm_sec,pstElevator->id,upnum);
            }
            pthread_mutex_unlock(&gstPersonQueue->stMutex);
            if(pstElevator->personCount)
            {
                up = 1;
            }
        }
        else
        {
            if(pstElevator->personCount)
            {
                downnum = 0;
                //printf("Down-IDS");
                dlist_for_each_safe(pos,next,&pstElevator->head)
                {    
                    person = dlist_entity(person_t,node,pos);
                    if(person->floor == pstElevator->floor)
                    {
                        downnum++;
                        dlist_del(pos);
                        //printf(" %d ",person->id);
                        free(person);
                        pstElevator->downCount++;
                        pstElevator->personCount--;
                    }
                }
                //printf("\n");
            }

            if(pstElevator->personCount == 0)
            {
                up = 0;
            }
            time = (time_t)pstElevator->stime;
            p=localtime(&time);
            printf("[时间%d:%d:%d][电梯%d在%d层下了%d个人]\n",p->tm_hour,p->tm_min,p->tm_sec,pstElevator->id,pstElevator->floor,downnum);
            //printf("[Time%d:%d:%d][Elevator%d floor %d down %d persons]\n",p->tm_hour,p->tm_min,p->tm_sec,pstElevator->id,pstElevator->floor,downnum);
        }

        if(up)
        {
            if(pstElevator->floor < ELEVATOR_FLOOR_NUM)
            {
                pstElevator->floor++;
            }
        }
        else
        {   
            if(pstElevator->floor != 1)
            {
                pstElevator->floor--;
            }
            else
            {
                printf("[Elevator%d is on floor %d]\n",pstElevator->id,pstElevator->floor);
            }
        }

        usleep(1000000);
    }
}

int main(int argc, char **argv)
{
    int ret = 0;
    volatile int index = 0;
    pthread_t tid[ELEVATOR_NUM+1];

    time_t stime;
    time_queue_t *pstTimeQueue = NULL;
    person_queue_t  *pstPersonQueue = NULL;
    elevator_t *pstElevator = NULL;

    pstTimeQueue = (time_queue_t *)malloc(sizeof(time_queue_t));
    if(!pstTimeQueue)
    {
        ret = -1;
        goto Error;
    }
    memset(pstTimeQueue,0,sizeof(time_queue_t));
    pstPersonQueue = (person_queue_t *)malloc(sizeof(person_queue_t));
    if(!pstPersonQueue)
    {
        ret = -1;
        goto Error;
    }
    memset(pstPersonQueue,0,sizeof(person_queue_t));
    pstElevator = (elevator_t *)malloc(sizeof(elevator_t)*ELEVATOR_NUM);
    if(!pstElevator)
    {
        ret = -1;
        goto Error;
    }
    memset(pstElevator,0,sizeof(elevator_t)*ELEVATOR_NUM);

    /*init*/
    dlist_init(&pstTimeQueue->head);
    pstTimeQueue->runPerSeconds = 1;
    dlist_init(&pstPersonQueue->head);
    pthread_mutex_init(&pstPersonQueue->stMutex,NULL);

    stime = time(NULL);
    for(index=0;index<ELEVATOR_NUM;index++)
    {
        dlist_init(&pstElevator[index].head);
        pstElevator[index].stime=stime;
        pstElevator[index].floor=1;
        pstElevator[index].id=index+1;
    }

    gstPersonQueue = pstPersonQueue;
    /*add time*/
    for(index=2;index<=ELEVATOR_FLOOR_NUM;index++)
    {
        ret = add_timer(pstTimeQueue,time_proc,index);
        if(ret)
        {
            goto Error;
        }
    }

    for(index=0; index< ELEVATOR_NUM+1; index++)
    {
        if(index >0 )
        {
            ret = pthread_create(&tid[index],NULL,elevator_run,(void *)(&pstElevator[index-1]));
        }
        else
        {
            ret = pthread_create(&tid[index],NULL,start_timer,(void *)pstTimeQueue);
        }
        if(ret)
        {
            goto Error;
        }
    }

    while(1);
Error:
    if(pstTimeQueue)
    {
        free(pstTimeQueue);
    }
    if(pstTimeQueue)
    {
        free(pstPersonQueue);
    }
    if(pstElevator)
    {
        free(pstElevator);
    }

    return ret;
}

运行结果:

[ELEVATOR:3] running!
[Elevator3 is on floor 1]
[ELEVATOR:4] running!
[Elevator4 is on floor 1]
[ELEVATOR:2] running!
[Elevator2 is on floor 1]
[ELEVATOR:1] running!
[Elevator1 is on floor 1]
[Elevator3 is on floor 1]
[Elevator4 is on floor 1]
[Elevator2 is on floor 1]
[Elevator1 is on floor 1]
[Elevator3 is on floor 1]
[Elevator4 is on floor 1]
[Elevator2 is on floor 1]
[Elevator1 is on floor 1]
[Elevator3 is on floor 1]
[Elevator4 is on floor 1]
[Elevator2 is on floor 1]
[Elevator1 is on floor 1]
[时间9:33:27][电梯3在1层上了1个人]
[Elevator4 is on floor 1]
[Elevator2 is on floor 1]
[Elevator1 is on floor 1]
[时间9:33:28][电梯3在2层下了1个人]
[时间9:33:28][电梯4在1层上了1个人]
[Elevator2 is on floor 1]
[Elevator1 is on floor 1]
[时间9:33:29][电梯3在1层上了3个人]
[时间9:33:29][电梯4在2层下了0个人]
[Elevator2 is on floor 1]
[Elevator1 is on floor 1]
[时间9:33:30][电梯3在2层下了1个人]
[时间9:33:30][电梯4在3层下了1个人]
[时间9:33:30][电梯2在1层上了1个人]
[Elevator1 is on floor 1]
[时间9:33:31][电梯3在3层下了0个人]
[时间9:33:31][电梯4在2层下了0个人]
[时间9:33:31][电梯2在2层下了0个人]
[时间9:33:31][电梯1在1层上了3个人]
[时间9:33:32][电梯3在4层下了1个人]
[时间9:33:32][电梯4在1层上了2个人]
[时间9:33:32][电梯2在3层下了0个人]
[时间9:33:32][电梯1在2层下了1个人]
[时间9:33:33][电梯3在3层下了0个人]
[时间9:33:33][电梯4在2层下了0个人]
[时间9:33:33][电梯2在4层下了0个人]
[时间9:33:33][电梯1在3层下了1个人]
[时间9:33:34][电梯3在2层下了0个人]
[时间9:33:34][电梯4在3层下了0个人]
[时间9:33:34][电梯2在5层下了1个人]
[时间9:33:34][电梯1在4层下了0个人]
[时间9:33:35][电梯3在1层上了11个人]
[时间9:33:35][电梯4在4层下了0个人]
[时间9:33:35][电梯2在4层下了0个人]
[时间9:33:35][电梯1在5层下了0个人]
[时间9:33:36][电梯3在2层下了2个人]
[时间9:33:36][电梯4在5层下了0个人]
[时间9:33:36][电梯2在3层下了0个人]
[时间9:33:36][电梯1在6层下了1个人]
[时间9:33:37][电梯3在3层下了1个人]
[时间9:33:37][电梯4在6层下了0个人]
[时间9:33:37][电梯2在2层下了0个人]
[时间9:33:37][电梯1在5层下了0个人]
[时间9:33:38][电梯3在4层下了1个人]
[时间9:33:38][电梯4在7层下了1个人]
[时间9:33:38][电梯2在1层上了5个人]
[时间9:33:38][电梯1在4层下了0个人]

附件:

[elevator.c][1]