自己寫的alarm_cond

 

#include<stdio.h>
#include"errors.h"
#include<pthread.h>
#include<time.h>
typedef struct alarm_tag{
int        seconds;
time_t     alarm_time;
char       message[64];
struct alarm_tag *link;
}alarm_t;
alarm_t *alarm_list=NULL;
pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_t=PTHREAD_COND_INITIALIZER;
time_t current_time=0;
void insert(alarm_t *alarm)
{
    int status;
     alarm_t **last, *next;

     last = &alarm_list;
     next = *last;
     while (next != NULL)
     {
         if (next->alarm_time >= alarm->alarm_time)
         {
             alarm->link = next;
             *last = alarm;
             break;
         }
         last = &next->link;
         next = next->link;
     }
     if (next == NULL) {
         *last = alarm;
         alarm->link = NULL;
     }

/*注意這裏鏈表的插入方法,標準的鏈表插入中,需要分情況討論,隊頭,隊中,隊尾,這裏把隊頭和隊中進行了合併,利用的是一個**last指針,這個指針在剛開始的時候保存的是隊頭的地址,如果不需要在隊頭插入,利用last=&next->link,可以保存下一個的節點的地址,找到合適的插入地址,讓last指向alarm,alarm指向next即可。本質上和鏈表的插入方法是一樣的,但是巧妙利用了指針。

剛纔仔細考慮才知道自己一直存在的誤區是鏈頭指針不是元素,它是指向第一個元素的,每個元素都有一個指針指向它,那麼只要讓這個指向元素的指針鏈進行傳遞就可以了,這也就是上面的代碼表示的含義。讓last指向這個指針鏈,但是因爲這個指針鏈有兩個名字,alarm_list和next->link,所以找一個再找一個指針來指向它們,這就是**last。*/
if(current_time==0||current_time>alarm->alarm_time)
{
   current_time=alarm->alarm_time;
   status=pthread_cond_signal(&cond_t);
   if(status!=0)
    err_abort(status,"Signal cond");
}
}


void *alarm_wait(void *arg)
{
struct timespec cond_time;
alarm_t *alarm;
time_t now;
int status,expiration;

status=pthread_mutex_lock(&mutex);
if(status!=0)
   err_abort(status,"mutex lock");

while(1)
{
   current_time=0;
   while(alarm_list==NULL)
   {
   status=pthread_cond_wait(&cond_t,&mutex);
   if(status!=0)
     err_abort(status,"alarm wait");
   }
   alarm=alarm_list;
   alarm_list=alarm->link;//這一句保證了當前正在使用的鬧鈴已經不在隊列當中
   now=time(NULL);
   cond_time.tv_sec=alarm->alarm_time;
   cond_time.tv_nsec=0;
   current_time=alarm->alarm_time;
   expiration=0;
   if(alarm->alarm_time>now)
   {
    while(current_time==alarm->alarm_time)
    {
     status=pthread_cond_timedwait(&cond_t,&mutex,&cond_time);
     if(status==ETIMEDOUT)
     {
      expiration=1;
      break;
     }
    if(status!=0)
      err_abort(status,"alarm waittime");
    }
   if(!expiration)
    insert(alarm);
   }
   else expiration=1;
   if(expiration)
   {
    printf("%d,%s/n",alarm->seconds,alarm->message);
    free(alarm);//釋放空間
   }
}
}
int main(){
pthread_t wait;
alarm_t *new_alarm;
int status;

status = pthread_create(&wait,NULL,alarm_wait,NULL);
if(status!=0)
   err_abort(status,"create alarm thread");
while(1)
{
   printf ("Alarm> ");
   new_alarm=(alarm_t*)malloc(sizeof(alarm_t));
   scanf("%d %s",&new_alarm->seconds,new_alarm->message);//直接scanf也是可以的,當然這裏沒有原程序的糾錯機制,可以另外加上

   new_alarm->alarm_time=time(NULL)+new_alarm->seconds;
   status=pthread_mutex_lock(&mutex);//這裏的操作是必須的,保證兩個線程對鏈表的操作是互斥的,以防止插入元素過程中,等待線程啓動,造成不可知的後果
   if(status!=0)
     err_abort(status,"mutex lock");
   insert(new_alarm);
   status=pthread_mutex_unlock(&mutex);
   if(status!=0)
     err_abort(status,"mutex unlock");
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章