感觉定义一个好的结构体,可以实现很强大的功能。
本程序是利用信号里面的知识来实现。功能是多任务定时器,有多个定时器,每个定时器都可以实现自己的功能(多少秒后打印任务,或者是周期性打印任务)。每个定时器返回自己的id,通过id来操控定时器任务取消,等待定时器结束(收尸任务)。
anytimer.h
#ifndef ANYTIMER_H__
#define ANYTIMER_H__
#define JOB_MAX 1024
typedef void at_addjob_t(void*);
int at_addjob(int sec,at_addjob_t *jobp,void* arg);
/*
* return >= 0 成功,返回任务ID
* == -EINVAL 失败,参数非法
* == -ENOSPC 失败,数组满
* == -ENOMEM 失败,内存空间不足
**/
int at_addjob_repeat(int sec,at_addjob_t *jobp,void* arg);
/*
* return >= 0 成功,返回任务ID
* == -EINVAL 失败,参数非法
* == -ENOSPC 失败,数组满
* == -ENOMEM 失败,内存空间不足
**/
int at_canceljob(int id);
/*
* return == 0 取消,指定任务成功取消
* == -EINVAL 失败,参数非法
* == -EBUSY 失败,任务已完成
* == -ECANCELED 失败,指定任务重复取消
**/
int at_waitjob(int id);
/*
* return == 0 取消,指定任务成功释放
* == -EINVAL 失败,参数非法
**/
#endif
anytimer.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <signal.h>
#include "anytimer.h"
enum
{
STATE_RUNNING = 1,
STATE_CANCEL,
STATE_OVER
};
struct at_job_st
{
int job_state;
int sec;
int time_remain;
int repeat;
at_addjob_t *jobp;
void *arg;
};
static struct at_job_st *job[JOB_MAX];
static int inited = 0;
struct sigaction sa_save;
static void module_unload(void)
{
struct itimerval itv;
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 0;
if(setitimer(ITIMER_REAL, &itv, NULL) < 0)
{
perror("setitimer()");
exit(1);
}
if(sigaction(SIGALRM, &sa_save, NULL) <0)
{
perror("sigaction()");
exit(1);
}
}
static void alrm_sigaction(int num, siginfo_t *infop, void *unused)
{
int i;
for(i=0; i<JOB_MAX; i++)
{
if(job[i] != NULL && job[i]->job_state == STATE_RUNNING)
{
job[i]->time_remain--;
if(job[i]->time_remain == 0)
{
job[i]->jobp(job[i]->arg);
if(job[i]->repeat == 1)
{
job[i]->time_remain = job[i]->sec;
}
else
{
job[i]->job_state = STATE_OVER;
}
}
}
}
}
static void module_load(void)
{
struct sigaction sa;
struct itimerval itv;
sa.sa_sigaction = alrm_sigaction;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
if(sigaction(SIGALRM, &sa, &sa_save) <0)
{
perror("sigaction()");
exit(1);
}
itv.it_interval.tv_sec = 1;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 1;
itv.it_value.tv_usec = 0;
if(setitimer(ITIMER_REAL, &itv, NULL) < 0)
{
perror("setitimer()");
exit(1);
}
atexit(module_unload);
}
static int get_job_pos(void)
{
int i;
for(i=0; i<JOB_MAX; i++)
{
if(job[i] == NULL)
return i;
}
return -1;
}
int at_addjob(int sec,at_addjob_t *jobp,void* arg)
/*
* return >= 0 成功,返回任务ID
* == -EINVAL 失败,参数非法
* == -ENOSPC 失败,数组满
* == -ENOMEM 失败,内存空间不足
**/
{
struct at_job_st *me;
int pos;
if(!inited)
{
module_load();
inited = 1;
}
if(sec < 0)
return -EINVAL;
me = malloc(sizeof(*me));
if(me == NULL)
return -ENOMEM;
me->job_state = STATE_RUNNING;
me->sec = sec;
me->time_remain = me->sec;
me->jobp = jobp;
me->arg = arg;
me->repeat = 0;
pos = get_job_pos();
if(pos <0)
return -ENOSPC;
job[pos] = me;
return pos;
}
int at_addjob_repeat(int sec,at_addjob_t *jobp,void* arg)
/*
* return >= 0 成功,返回任务ID
* == -EINVAL 失败,参数非法
* == -ENOSPC 失败,数组满
* == -ENOMEM 失败,内存空间不足
**/
{
struct at_job_st *me;
int pos;
if(!inited)
{
module_load();
inited = 1;
}
if(sec < 0)
return -EINVAL;
me = malloc(sizeof(*me));
if(me == NULL)
return -ENOMEM;
me->job_state = STATE_RUNNING;
me->sec = sec;
me->time_remain = me->sec;
me->jobp = jobp;
me->arg = arg;
me->repeat = 1;
pos = get_job_pos();
if(pos <0)
return -ENOSPC;
job[pos] = me;
return pos;
}
int at_canceljob(int id)
/*
* return == 0 取消,指定任务成功取消
* == -EINVAL 失败,参数非法
* == -EBUSY 失败,任务已完成
* == -ECANCELED 失败,指定任务重复取消
**/
{
if(id < 0 || id > JOB_MAX || job[id] == NULL)
return -EINVAL;
if(job[id]->job_state == STATE_CANCEL)
return -ECANCELED;
if(job[id]->job_state == STATE_OVER)
return -EBUSY;
job[id]->job_state = STATE_CANCEL;
return 0;
}
int at_waitjob(int id)
/*
* return == 0 取消,指定任务成功释放
* == -EINVAL 失败,参数非法
* == -EBUSY 失败,指定任务为周期性任务
**/
{
if(id <0 || id > JOB_MAX || job[id] == NULL)
return -EINVAL;
if(job[id]->repeat == 1)
{
return -EBUSY;
}
while(job[id]->job_state == STATE_RUNNING) //一直等到job状态变换才能取消。
pause();
if(job[id]->job_state == STATE_OVER || job[id]->job_state == STATE_CANCEL)
{
free(job[id]);
job[id] = NULL;
}
return 0;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "anytimer.h"
static void f1(void *p)
{
printf("f1():%s\n", p);
}
static void f2(void *p)
{
printf("f2():%s\n", p);
}
int main(int argc, char **argv)
{
int job1, job2;
#if 0
job1 = at_addjob(2, f1, "aa");
if(job1 < 0)
{
fprintf(stderr, "job1():%s\n", strerror(-job1));
exit(1);
}
job2 = at_addjob(5, f2, "bb");
if(job2 < 0)
{
fprintf(stderr, "job2():%s\n", strerror(-job1));
exit(1);
}
#endif
job1 = at_addjob_repeat(2, f1, "aa");
if(job1 < 0)
{
fprintf(stderr, "job1():%s\n", strerror(-job1));
exit(1);
}
while(1)
{
write(1, "*", 1);
sleep(1);
}
exit(1);
}
定义周期性任务结果
这里有个缺陷就是wait_job不能一直等待,不然得阻塞。只能先取消任务at_canceljob(),让后at_waitjob()
2,有限状态机的完善。
增加cancel和wait功能。因为是用线程写的,所以用全局互斥锁对临界区资源rel_job互斥访问。对cancel进行实现的时候,由于是对一个节点进行访问,可以不用使用全局锁,而是用一个节点里面的锁,对状态进行改变。对wait功能进行实现的时候,想法是一直等待状态发生改变(pthread_cond_wait()用通知法),由于要释放rel_job里面的一个节点,所以又得访问临界区资源rel_job,这就形成了一个死穴了。
relay.h
#ifndef RELAY_H__
#define RELAY_H__
#include <stdint.h>
#define REL_JOBMAX 10000
struct rel_stat_st
{
int state;
int fd1;
int fd2;
int64_t count12, count21;
};
int rel_addjob(int fd1, int fd2);
/*
return >= 0 成功,返回当前任务ID
== -EINVAL 失败,参数非法
== -ENOSPC 失败,任务数组满
== -ENOMEM 失败,内存分配有误
*/
int rel_canceljob(int id);
/*
return == 0 成功,指定任务成功取消
== -EINVAL 失败,参数非法
== -EBUSY 失败,任务早已被取消
*/
int rel_waitjob(int id, struct rel_stat_st*);
/*
return == 0 成功,指定任务已终止并返回状态
== -EINVAL 失败,参数非法
*/
int rel_statjob(int id, struct rel_stat_st*);
/*
return == 0 成功,指定任务状态返回
== -EINVAL 失败,参数非法
*/
#endif
relay.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include "relay.h"
#define BUFSIZE 1024
enum
{
STATE_R=1,
STATE_W,
STATE_E,
STATE_T
};
enum
{
STATE_RUNNING=1,
STATE_CANCELED,
STATE_OVER
};
struct fsm_st
{
int state;
int sfd;
int dfd;
char buf[BUFSIZE];
int len;
int pos;
char *errstr;
};
struct rel_job_st
{
int fd1, fd2;
int job_state;
struct fsm_st fsm12, fsm21;
int fd1_save, fd2_save;
pthread_mutex_t mtx; //互斥访问状态
pthread_cond_t cond;
};
static struct rel_job_st *rel_job[REL_JOBMAX];
static pthread_mutex_t job_mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_once_t once_init=PTHREAD_ONCE_INIT;
void fsm_driver(struct fsm_st *fsm)
{
int ret;
switch(fsm->state)
{
case STATE_R:
ret = read(fsm->sfd, fsm->buf, BUFSIZE);
if(ret < 0)
{
if(errno == EAGAIN)
fsm->state = STATE_R;
else
{
fsm->errstr = "read()";
fsm->state = STATE_E;
}
}
else if(ret == 0)
{
fsm->state = STATE_T;
}
else{
fsm->state = STATE_W;
fsm->len = ret;
fsm->pos = 0;
}
break;
case STATE_W:
ret = write(fsm->dfd, fsm->buf + fsm->pos, fsm->len);
if(ret < 0)
{
if(errno == EAGAIN)
fsm->state = STATE_W;
else
{
fsm->errstr = "write()";
fsm->state = STATE_E;
}
}
else
{
if(ret < fsm->len)
{
fsm->pos += ret;
fsm->len -= ret;
fsm->state = STATE_W;
}
else
fsm->state = STATE_R;
}
break;
case STATE_E:
perror(fsm->errstr);
fsm->state = STATE_T;
break;
case STATE_T:
break;
default:
abort();
}
}
static int get_pos_unlock()
{
int i;
for(i=0; i<REL_JOBMAX; i++)
{
if(rel_job[i] == NULL)
return i;
}
return -1;
}
static void *thr_worker(void *arg)
{
printf("%s:%d\n", __FUNCTION__, __LINE__);
int i;
while(1)
{
pthread_mutex_lock(&job_mtx);
for(i=0; i<REL_JOBMAX; i++)
{
if(rel_job[i] != NULL)
{
pthread_mutex_lock(&rel_job[i]->mtx);
if(rel_job[i]->job_state == STATE_RUNNING)
{
fsm_driver(&rel_job[i]->fsm12);
fsm_driver(&rel_job[i]->fsm21);
if(rel_job[i]->fsm12.state == STATE_T && rel_job[i]->fsm21.state == STATE_T)
{
rel_job[i]->job_state = STATE_OVER;
}
}
pthread_cond_broadcast(&rel_job[i]->cond);
pthread_mutex_lock(&rel_job[i]->mtx);
}
}
pthread_mutex_unlock(&job_mtx);
}
}
static void module_load(void)
{
printf("%s:%d\n", __FUNCTION__, __LINE__);
int err;
pthread_t tid_relayer;
err = pthread_create(&tid_relayer, NULL, thr_worker, NULL);
if(err)
{
fprintf(stderr, "pthread_create():%s\n", strerror(err));
exit(1);
}
}
int rel_addjob(int fd1, int fd2)
{
struct rel_job_st *me;
int pos;
pthread_once(&once_init, module_load);
printf("%s:%d\n", __FUNCTION__, __LINE__);
me = malloc(sizeof(*me));
if(me == NULL)
return -ENOMEM;
me->fd1 = fd1;
me->fd2 = fd2;
me->job_state = STATE_RUNNING;
me->fd1_save = fcntl(me->fd1, F_GETFL);
fcntl(me->fd1, F_SETFL, me->fd1_save|O_NONBLOCK);
me->fd2_save = fcntl(me->fd2, F_GETFL);
fcntl(me->fd2, F_SETFL, me->fd2_save|O_NONBLOCK);
me->fsm12.sfd = me->fd1;
me->fsm12.dfd = me->fd2;
me->fsm12.state = STATE_R;
me->fsm21.sfd = me->fd2;
me->fsm21.dfd = me->fd1;
me->fsm21.state = STATE_R;
pthread_mutex_init(&me->mut, NULL);
pthread_cond_init(&me->cond, NULL);
pthread_mutex_lock(&job_mtx);
pos = get_pos_unlock();
if(pos < 0)
{
pthread_mutex_unlock(&job_mtx);
fcntl(me->fd1, F_SETFL, me->fd1_save);
fcntl(me->fd2, F_SETFL, me->fd2_save);
free(me);
return -ENOSPC;
}
rel_job[pos] = me;
pthread_mutex_unlock(&job_mtx);
return pos;
}
int rel_canceljob(int id)
/*
return == 0 成功,指定任务成功取消
== -EINVAL 失败,参数非法
== -EBUSY 失败,任务早已被取消
*/
{
pthread_mutex_lock(&rel_job[id]->mtx);
if(id > REL_JOBMAX || id < 0 || rel_job[id] == NULL)
{
pthread_mutex_unlock(&rel_job[id]->mtx);
return -EINVAL;
}
if(rel_job[id]->state == STATE_CANCELED)
{
pthread_mutex_unlock(&rel_job[id]->mtx);
return -EBUSY;
}
rel_job[id]->state = STATE_CANCELED;
pthread_cond_broadcast(&rel_job[id]->cond);
pthread_mutex_unlock(&rel_job[id]->mtx);
return 0;
}
int rel_waitjob(int id, struct rel_stat_st* stat)
/*
return == 0 成功,指定任务已终止并返回状态
== -EINVAL 失败,参数非法
转念一想好像释放job点的时候,还是会访问修改rel_job里面的内容
*/
{
pthread_mutex_lock(&rel_job[id]->mtx);
if(id > REL_JOBMAX || id < 0 || rel_job[id] == NULL)
{
pthread_mutex_unlock(&job_mtx);
return -EINVAL;
}
while(rel_job[id].state == STATE_RUNNING)
{
pthread_cond_wait(&rel_job[id]->cond, &rel_job[id]->mtx); //解锁,等待
}
if (rel_job[id].state == STATE_CANCELED || rel_job[id].state == STATE_OVER)
{
free(rel_job[id]);
rel_job[id] = NULL;
}
pthread_mutex_unlock(&rel_job[id]->mtx);
return 0;
}
int rel_statjob(int id, struct rel_stat_st*)
/*
return == 0 成功,指定任务状态返回
== -EINVAL 失败,参数非法
*/
{
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "relay.h"
#define TTY1 "/dev/tty9"
#define TTY2 "/dev/tty8"
#define TTY3 "/dev/tty10"
#define TTY4 "/dev/tty11"
int main()
{
int fd1, fd2, fd3, fd4;
int job1, job2;
fd1 = open(TTY1, O_RDWR);
if(fd1 < 0)
{
perror("open()");
exit(1);
}
write(fd1, "TTY1\n", 5);
fd2 = open(TTY2, O_RDWR);
if(fd2 < 0)
{
perror("open()");
exit(1);
}
write(fd2, "TTY2\n", 5);
job1 = rel_addjob(fd1, fd2);
if(job1 <0)
{
fprintf(stderr, "rel_addjob():%s\n", strerror(-job1));
exit(1);
}
//job2
fd3 = open(TTY3, O_RDWR);
if(fd3 < 0)
{
perror("open()");
exit(1);
}
write(fd3, "TTY3\n", 5);
fd4 = open(TTY4, O_RDWR);
if(fd4 < 0)
{
perror("open()");
exit(1);
}
write(fd4, "TTY4\n", 5);
job2 = rel_addjob(fd3, fd4);
if(job2 <0)
{
fprintf(stderr, "rel_addjob():%s\n", strerror(-job2));
exit(1);
}
while (1)
pause();
close(fd1);
close(fd2);
close(fd3);
close(fd4);
exit(0);
}