Linux C任务计数器实现-信号实现

感觉定义一个好的结构体,可以实现很强大的功能。

本程序是利用信号里面的知识来实现。功能是多任务定时器,有多个定时器,每个定时器都可以实现自己的功能(多少秒后打印任务,或者是周期性打印任务)。每个定时器返回自己的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);
	
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值