我目前正在考虑QTimer
实施的线程安全性。
在我的应用程序中,我使用bool isActive()
方法检查计时器是否正在运行。由于我打算也从其他线程使用这种方法,我的想法转到了线程安全考虑。
根据我的研究,方法bool isActive()
不是线程安全的。
以下是我的假设:
QTimer
(QTimer source code)的实现表明bool isActive()
只检查成员变量int id;
是否大于0:
inline bool isActive() const { return id >= 0; }
此成员变量在构造函数中使用INV_TIMER
初始化,-1
是int QObject::startTimer(int interval)
的定义。启动计时器时,它将被设置为/*! \overload start()
Starts or restarts the timer with the timeout specified in \l interval.
If \l singleShot is true, the timer will be activated only once.
*/
void QTimer::start()
{
if (id != INV_TIMER) // stop running timer
stop();
nulltimer = (!inter && single);
id = QObject::startTimer(inter);
}
的返回值。
isActive()
在QTimer::start()
期间从另一个帖子执行对bool isActive()
的调用时,我认为class SensorControl : public QObject
{
Q_OBJECT
public:
SensorControl(); // inits and interval-settings are done at implementation
bool Start()
{
QMutexLocker lock(&m_mutexTimer);
return m_pTimer->start();
}
void Stop()
{
QMutexLocker lock(&m_mutexTimer);
return m_pTimer->stop();
}
bool IsMeasuring() const
{
QMutexLocker lock(&m_mutexTimer);
return m_pTimer->isActive();
}
private:
QMutex m_mutexTimer;
QTimer* m_pTimer;
};
的返回值可能无效。
我很感激能够验证我的假设的人的意见。
为了达到线程安全性,我只需使用互斥锁将我的调用打包到计时器,就像下面显示的代码片段一样。
/**
*
*/
package com.shashank.java8.parallel_stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @author pooja
*
*/
public class Sample {
public static int processUrl(String url) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Running Thread " + Thread.currentThread());
return url.length();
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
usingExecutor();
usingParallelStream();
}
public static void usingParallelStream() {
Date start = new Date();
// TODO Auto-generated method stub
int total = buildUrlsList().parallelStream().mapToInt(Sample::processUrl).reduce(0, Integer::sum);
Date end = new Date();
System.out.println(total);
System.out.println((end.getTime() - start.getTime()) / 1000);
}
public static void usingExecutor() throws Exception {
Date start = new Date();
ExecutorService executorService = Executors.newFixedThreadPool(100);
List<Future> futures = new ArrayList<>();
for (String url : buildUrlsList()) {
futures.add(executorService.submit(() -> processUrl(url)));
}
// iterate through the future
int total = 0;
for (Future<Integer> future : futures) {
total += future.get();
}
System.out.println(total);
Date end = new Date();
System.out.println((end.getTime() - start.getTime()) / 1000);
}
public static List<String> buildUrlsList() {
return Arrays.asList("url1", "url2", "url3", "url4", "url5", "url6", "url7", "url8", "url9");
}
}
答案 0 :(得分:1)
如果您想仅从另一个线程调用QTimer::isActive
,那么您的解决方案看起来很安全。 isActive
仅访问id
成员变量,因此您需要互斥保护对id
的所有写入以及从您的线程中读取id
。您为isActive
和stop
执行了此操作,因此看起来不错。
请注意,如果您曾调用QTimer
写入id
的其他方法,则会得到未定义的行为。因此,请注意不要调用QTimer::setInterval()
,QTimer::~QTimer()
(!)等内容。也不要使用单一计时器,因为它会写入id
中的QTimer::timerEvent()
。
通常包装现有类并添加互斥锁是危险的,这是否有效取决于所述类的内部,并且很难检查所有情况。此外,内部可能在下一个Qt版本中发生变化,可能在下一个版本中QTimer::timerEvent()
将无条件地更改id
,并且您的解决方案不再是线程安全的。
所以,虽然你的方法有效,但总的来说我会反对它。