如何在android下采用相对时间,实现超时等待的功能
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在android下采用相对时间,实现超时等待的功能相关的知识,希望对你有一定的参考价值。
参考技术A 一、函数功能说明pthread_cond_timedwait 等待一个条件变量,或者超时就会返回
POSIX有两种时钟类型
1、CLOCK_REALTIME: 系统范围内的实时时钟,是个时钟,可以通过命令等方式修改该系统时间.
2、CLOCK_MONOTONIC:系统起机时到现在的时间,不能被设置和修改.
pthread_cond_timedwait()在没有设置条件变量属性的时候,默认用的是CLOCK_REALTIME时间,
因此在极端情况下会出现实际等待的时间与设置的超时时间不同。
所以,对于linux的超时等待功能,最好是使用CLOCK_MONOTONIC进行实现,并且通过pthread_condattr_setclock实现。
而对于android系统而言,是不支持pthread_condattr_setclock,通过验证可以采用函数pthread_cond_timedwait_monotonic实现。
下面直接给出代码的实现功能。
二、超时等待功能
[cpp] view plain copy
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/times.h>
#include <unistd.h>
#include <time.h>
static pthread_mutex_t s_mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t s_cond = PTHREAD_COND_INITIALIZER;
void PthreadAttr_Init(void);
unsigned long long getSysTime(void);
void waitTimeout(void);
void PthreadAttr_Init(void)
#if defined(ANDROID)
#else
pthread_condattr_t cattr;
int iRet = -1;
iRet = pthread_condattr_init(cattr);
if (iRet != 0)
return;
pthread_mutex_init(s_mut, NULL);
pthread_condattr_setclock(cattr, CLOCK_MONOTONIC);
pthread_cond_init(s_cond, cattr);
pthread_condattr_destroy(cattr);
#endif
return;
void waitTimeout(void)
unsigned long long ullbefore = getSysTime();
unsigned long long ullafter = 0;
#if defined(ANDROID)
#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) // 支持ANDROID下NDK的编译,采用相对时间
struct timespec outtime;
memset(outtime, 0x00, sizeof(struct timespec ));
clock_gettime(CLOCK_MONOTONIC, outtime);
outtime.tv_sec += 2;
pthread_mutex_lock(s_mut);
pthread_cond_timedwait_monotonic(s_cond,s_mut, outtime);
pthread_mutex_unlock(s_mut);
ullafter = getSysTime();
printf("####01 interval[%lld] ms\n", ullafter - ullbefore);
#else //支持ANDROID下NDK的编译,采用绝对时间
struct timeval now;
struct itmespec outtime;
gettimeofday(now, NULL);
outtime.tv_sec = now..tv_sec + 3;
outtime.tv_nsec = now.tv_usec * 1000;
pthread_mutex_lock(s_mut);
pthread_cond_timedwait(s_cond, s_mut, outtime);
pthread_mutex_unlock(s_mut);
ullafter = getSysTime();
printf("####02 interval[%lld] ms\n", ullafter - ullbefore);
#endif
#else // 支持LINUX下的编译,采用绝对时间
struct timespec outtime;
memset(outtime, 0x00, sizeof(struct timespec ));
clock_gettime(CLOCK_MONOTONIC, outtime);
outtime.tv_sec += 4;
pthread_mutex_lock(s_mut);
pthread_cond_timedwait(s_cond, s_mut, outtime);
pthread_mutex_unlock(s_mut);
ullafter = getSysTime();
printf("####03 interval[%lld] ms\n", ullafter - ullbefore);
#endif
return;
unsigned long long getSysTime(void)
unsigned long long milliseconds = 0;
struct tms t_tmsTime;
clock_t t_CurTime;
static int s_clks_per_sec = 0;
if (s_clks_per_sec == 0)
s_clks_per_sec = sysconf(_SC_CLK_TCK);
if (s_clks_per_sec == 0)
return 0;
t_CurTime = times(t_tmsTime);
if (1000 % s_clks_per_sec == 0)
milliseconds = (1000 /s_clks_per_sec)*(unsigned long long )t_CurTime;//换算成毫秒
else
milliseconds = 1000 * (unsigned long long )t_CurTime/s_clks_per_sec;//换算成毫秒
return milliseconds;
int main(void)
PthreadAttr_Init();
waitTimeout();
return 0;
编译命令:
gcc test_ptthrad_conf_timewait_monotonic.c -o test_ptthrad_conf_timewait_monotonic -lpthread -lrt
linux下的测试结果:
####03 interval[4010] ms
使用Promise.race实现超时机制取消XHR请求
我们来看一下如何使用Promise.race来实现超时机制。
当然XHR有一个 timeout 属性,使用该属性也可以简单实现超时功能,但是为了能支持多个XHR同时超时或者其他功能,我们采用了容易理解的异步方式在XHR中通过超时来实现取消正在进行中的操作。
让Promise等待指定时间
首先我们来看一下如何在Promise中实现超时。
所谓超时就是要在经过一定时间后进行某些操作,使用 setTimeout 的话很好理解。
首先我们来串讲一个单纯的在Promise中调用 setTimeout 的函数。
//delayPromise.js
function delayPromise(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
Promise.race中的超时
Promise.race就是一组promise中只要有一个返回,其它的promise就不会执行后续回调(无论错误还是成功)
var winnerPromise = new Promise(function (resolve) {
setTimeout(function () {
console.log(\'this is winner\');
resolve(\'this is winner\');
}, 4);
});
var loserPromise = new Promise(function (resolve) {
setTimeout(function () {
console.log(\'this is loser\');
resolve(\'this is loser\');
}, 1000);
});
// 第一个promise变为resolve后程序停止,第二个promise不会进入回调
Promise.race([winnerPromise, loserPromise]).then(function (value) {
console.log(value); // => \'this is winner\'
});
我们可以将刚才的 delayPromise 和其它promise对象一起放到 Promise.race 中来是实现简单的超时机制。
//simple-timeout-promise.js
function delayPromise(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
function timeoutPromise(promise, ms) {
var timeout = delayPromise(ms).then(function () {
throw new Error(\'Operation timed out after \' + ms + \' ms\');
});
return Promise.race([promise, timeout]);//返回taskPromise和timeoutPromise组成的Promise.race
}
定制TimeoutError对象
//TimeoutError
class TimeoutError extends Error{
constructor(msg){
super(msg)
}
}
实例
class TimeoutError extends Error{
constructor(msg){
super(msg)
}
}
function delayPromise(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
function timeoutPromise(promise, ms) {
var timeout = delayPromise(ms).then(function () {
throw new TimeOutError(\'Operation timed out after \' + ms + \' ms\');
});
return Promise.race([promise, timeout]);
}
// 运行示例
var taskPromise = new Promise(function(resolve){
// 随便一些什么处理
var delay = Math.random() * 2000;
setTimeout(function(){
resolve(delay + "ms");
}, delay);
});
timeoutPromise(taskPromise, 1000).then(function(value){
console.log("taskPromise在规定时间内结束 : " + value);
}).catch(function(error){
if(error instance of TimeoutError){
console.log("发生超时", error);
}
});
通过超时取消XHR操作
到这里,我想各位读者都已经对如何使用Promise来取消一个XHR请求都有一些思路了吧。
取消XHR操作本身的话并不难,只需要调用 XMLHttpRequest 对象的 abort() 方法就可以了。
为了能在外部调用 abort() 方法,我们先对之前本节出现的 getURL 进行简单的扩展,cancelableXHR 方法除了返回一个包装了XHR的promise对象之外,还返回了一个用于取消该XHR请求的abort方法。
//delay-race-cancel.js
function cancelableXHR(URL) {
var req = new XMLHttpRequest();
var promise = new Promise(function (resolve, reject) {
req.open(\'GET\', URL, true);
req.onload = function () {
if (req.status === 200) {
resolve(req.responseText);
} else {
reject(new Error(req.statusText));
}
};
req.onerror = function () {
reject(new Error(req.statusText));
};
req.onabort = function () {
reject(new Error(\'abort this request\'));
};
req.send();
});
var abort = function () {
// 如果request还没有结束的话就执行abort
// https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
if (req.readyState !== XMLHttpRequest.UNSENT) {
req.abort();
}
};
return {
promise: promise,
abort: abort
};
}
在这些问题都明了之后,剩下只需要进行Promise处理的流程进行编码即可。大体的流程就像下面这样。
通过 cancelableXHR 方法取得包装了XHR的promise对象和取消该XHR请求的方法
在 timeoutPromise 方法中通过 Promise.race 让XHR的包装promise和超时用promise进行竞争。
XHR在超时前返回结果的话
和正常的promise一样,通过 then 返回请求结果
发生超时的时候
抛出 throw TimeoutError 异常并被 catch
catch的错误对象如果是 TimeoutError 类型的话,则调用 abort 方法取消XHR请求
将上面的步骤总结一下的话,代码如下所示。
//delay-race-cancel-play.js
class TimeoutError extends Error{
constructor(msg){
super(msg)
}
}
function delayPromise(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
function timeoutPromise(promise, ms) {
var timeout = delayPromise(ms).then(function () {
return Promise.reject(new TimeoutError(\'Operation timed out after \' + ms + \' ms\'));
});
return Promise.race([promise, timeout]);
}
function cancelableXHR(URL) {
var req = new XMLHttpRequest();
var promise = new Promise(function (resolve, reject) {
req.open(\'GET\', URL, true);
req.onload = function () {
if (req.status === 200) {
resolve(req.responseText);
} else {
reject(new Error(req.statusText));
}
};
req.onerror = function () {
reject(new Error(req.statusText));
};
req.onabort = function () {
reject(new Error(\'abort this request\'));
};
req.send();
});
var abort = function () {
// 如果request还没有结束的话就执行abort
// https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
if (req.readyState !== XMLHttpRequest.UNSENT) {
req.abort();
}
};
return {
promise: promise,
abort: abort
};
}
var object = cancelableXHR(\'http://httpbin.org/get\');
// main
timeoutPromise(object.promise, 1000).then(function (contents) {
console.log(\'Contents\', contents);
}).catch(function (error) {
if (error instanceof TimeoutError) {
object.abort();
return console.log(error);
}
console.log(\'XHR Error :\', error);
});
上面的代码就通过在一定的时间内变为解决状态的promise对象实现了超时处理。
以上是关于如何在android下采用相对时间,实现超时等待的功能的主要内容,如果未能解决你的问题,请参考以下文章