2014年(1)
分类: LINUX
2014-03-12 23:11:48
#include
#include
#include
#include
#include
#include
int makethread(void *(*)(void*), void*);
pthread_mutexattr_t attr;
pthread_mutex_t mutex;
// fn is timeout_helper , arg is struct to_info
int makethread(void *(*fn)(void*), void *arg)
{
int err = 0;
pthread_t tid;
pthread_attr_t attr;
void *tret = NULL;
printf("this is makethread\n");
err = pthread_attr_init(&attr);
if (err != 0) {
printf("pthread_attr_init failed\n");
return err;
}
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置线程分离状态,当线程运行完后,自动回收资源
if (err == 0) {
err = pthread_create(&tid, &attr, fn, arg);//在这里arg传到fn当中
if (err != 0) {
printf("pthread_create failed\n");
goto FINISH;
} else {
printf("pthread_create success\n");
}
} else {
printf("pthread_attr_setdetachstate failed\n");
}
FINISH:
pthread_attr_destroy(&attr);//销毁线程属性
return err;
}
struct to_info {
void (*to_fn)(void *); /* function */
void *to_arg; /* argument */
struct timespec to_wait; /* time to wait */
};
#define SECTONSEC 1000000000 /* seconds to nanoseconds */
#define USECTONSEC 1000 /* microseconds to nanoseconds */
void err_exit(int err, const char *arg){
printf("ERROR: %d, DESC: %s\n", err, arg);
exit(0);
}
void* timeout_helper(void *arg)
{
struct to_info *tip;
tip = (struct to_info*)arg;
printf("this is timeout_helper\n");
printf("等待的秒数是:%d, 纳秒是:%d\n", tip->to_wait.tv_sec, tip->to_wait.tv_nsec);
nanosleep(&tip->to_wait, NULL);//第一个参数是等待唤醒的时间,中间可被信号中断。第二个参数是保留剩余的时候
(*tip->to_fn)(tip->to_arg);//调用retry函数
return 0;
}
void retry(void *arg)
{
pthread_mutex_lock(&mutex);
/* perform retry steps */
printf("this is retry\n");
pthread_mutex_unlock(&mutex);
}
// func is retry
void timeout(const struct timespec *when, void (*func)(void*), void *arg)
{
struct timespec now;
struct timeval tv;
struct to_info *tip;
int err;
printf("this is timeout\n");
gettimeofday(&tv, NULL);
now.tv_sec = tv.tv_sec;
now.tv_nsec = tv.tv_usec * USECTONSEC;//把时间换成纳秒
if ((when->tv_sec > now.tv_sec) ||
(when->tv_sec == now.tv_sec && when->tv_nsec > now.tv_nsec)) {//时间未到
tip = (struct to_info*)malloc(sizeof(struct to_info));
if (tip != NULL) {
tip->to_fn = func;/**初始化结构体*/
tip->to_arg = arg;
tip->to_wait.tv_sec = when->tv_sec - now.tv_sec;//要等待的秒数
if (when->tv_nsec >= now.tv_nsec) {
tip->to_wait.tv_nsec = when->tv_nsec - now.tv_nsec;
} else {
tip->to_wait.tv_sec--;
tip->to_wait.tv_nsec = SECTONSEC - now.tv_nsec + when->tv_nsec;
}
err = makethread(timeout_helper, (void*)tip);
if ( 0 == err) {
return;
}
}
}
/**
* We get here if (a) when <= now, or (b) malloc fails, or
* (c) we can't make a thread, so we just call the function now.
*/
(*func)(arg);
}
int main(void)
{
int err, condition, arg;
struct timeval tv;
struct timespec when;
condition = 1;
if ((err = pthread_mutexattr_init(&attr)) != 0) {
err_exit(err, "pthread_mutexattr_init failed");
}
/**/
if ((err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) != 0) {
err_exit(err, "can't set recursive type");
}
/**/
if ((err = pthread_mutex_init(&mutex, &attr)) != 0) {
err_exit(err, "can't create recursive mutex");
}
gettimeofday(&tv, NULL);
when.tv_sec = tv.tv_sec - 1;//设置超时执行,并且设置线程属性为PTHREAD_MUTEX_RECURSIVE用递归加锁方式,否则将会产生死锁
//when.tv_sec = tv.tv_sec + 1;//默认的线程属性非PTHREAD_MUTEX_RECURSIVE递归加锁方式,线程运行正常
when.tv_nsec = tv.tv_usec * USECTONSEC;
pthread_mutex_lock(&mutex);
if (condition) {
/* calculate target time "when" */
timeout(&when, retry, (void*)arg);
}
pthread_mutex_unlock(&mutex);
sleep(2);
exit(0);
}
/**
1. 注释128~130行(不设置递归互斥量),137行代替136行,超时1秒后,超时线程执行retry函数。由于主进程main和retry是在前后相隔1秒的时间间隔内分别获取互斥量的,因此不会引起互斥量的递归锁定,因此程序能够正确执行;
2. 注释128~130行(不设置递归互斥量),136行代替137行,则95行代码会被执行,main和retry在同一个进程里执行,互斥量嵌套锁定,因此会引起死锁;
3. 解除128~130行的注释(设置递归互斥量),136行代替137行,尽管103行依旧会执行,但是互斥量设置了递归属性,因此程序也能正确执行。
*/