| (同じ利用者による、間の2版が非表示) | |||
| 1,145行目: | 1,145行目: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | |||
== ファイルの排他制御 (QFile::tryLockメソッドの使用) == | |||
<code>QFile</code>クラスの<code>tryLock</code>メソッドとは、指定した時間を最大待機時間として、ロックを取得しようとするものである。<br> | |||
<br> | |||
bool tryLock(int timeout) | |||
<br> | |||
具体的には以下のような動作をする。<br> | |||
# tryLockメソッドを実行して、ファイルのロックの取得を試みる。 | |||
#: <br> | |||
# この間、システムは繰り返しロックの取得を試みる。<br>つまり、最大待機時間の間に何度もロックを確認する。 | |||
#: <br> | |||
# 以下のいずれかにより、tryLockメソッドが終了する。 | |||
#* ロックの取得に成功した場合 (trueを返す) | |||
#* 最大待機時間が経過してもロックが取得できなかった場合 (falseを返す) | |||
<br> | |||
つまり、tryLockメソッドは「最大待機時間の間に何度かロックを確認しながら待機する」という動作をする。<br> | |||
これにより、ファイルが利用可能になり次第すぐにロックを取得できるため、効率的にリソースを使用できる。<br> | |||
<br> | |||
最大待機時間以内にロックが解放された場合は、その時点でロックを取得してメソッドは終了する。<br> | |||
<br> | |||
以下の例では、複数のスレッドでファイルの読み書きを行っている。<br> | |||
各関数内でtryLockメソッドを使用して、3秒のタイムアウトでファイルのロックを試みている。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <QCoreApplication> | |||
#include <QFile> | |||
#include <QTextStream> | |||
#include <QtConcurrent> | |||
#include <QFuture> | |||
#include <QFutureSynchronizer> | |||
#include <QDebug> | |||
QString readFile(const QString &filePath) | |||
{ | |||
QFile file(filePath); | |||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | |||
qDebug() << "ファイルオープンエラー: " << file.errorString(); | |||
return QString(); | |||
} | |||
// 最大3秒まで待機 | |||
if (!file.tryLock(3000)) { | |||
qDebug() << "ファイルのロックに失敗 (読み取り)"; | |||
file.close(); | |||
return QString(); | |||
} | |||
QTextStream in(&file); | |||
QString content = in.readAll(); | |||
qDebug() << "データ: " << content; | |||
file.unlock(); // ファイルのロックを解除 | |||
file.close(); // ファイルを閉じる | |||
return content; | |||
} | |||
bool writeFile(const QString &filePath, const QString &content) | |||
{ | |||
QFile file(filePath); | |||
if (!file.open(QIODevice::ReadWrite | QIODevice::Append | QIODevice::Text)) { | |||
qDebug() << "ファイルオープンエラー: " << file.errorString(); | |||
return false; | |||
} | |||
// 最大3秒まで待機 | |||
if (!file.tryLock(3000)) { | |||
qDebug() << "ファイルのロックに失敗 (書き込み)"; | |||
file.close(); | |||
return false; | |||
} | |||
QTextStream out(&file); | |||
out << content << Qt::endl; | |||
qDebug() << "書き込みデータ: " << content; | |||
file.unlock(); // ファイルのロックを解除 | |||
file.close(); // ファイルを閉じる | |||
return true; | |||
} | |||
int main(int argc, char *argv[]) | |||
{ | |||
QCoreApplication a(argc, argv); | |||
QString filePath = "sample.txt"; | |||
// ファイルが存在しない場合は作成 | |||
QFile file(filePath); | |||
if (!file.exists()) { | |||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { | |||
QTextStream out(&file); | |||
out << "Initial content" << Qt::endl; | |||
file.close(); | |||
} | |||
} | |||
QFutureSynchronizer<void> synchronizer; | |||
// ファイルの読み込み (複数のスレッドの使用) | |||
for (int i = 0; i < 3; i++) { | |||
QFuture<QString> readFuture = QtConcurrent::run(readFile, filePath); | |||
synchronizer.addFuture(readFuture); | |||
} | |||
// ファイルの書き込み (複数のスレッドの使用) | |||
for (int i = 0; i < 3; i++) { | |||
QString content = QString("Concurrent write %1").arg(i); | |||
QFuture<bool> writeFuture = QtConcurrent::run(writeFile, filePath, content); | |||
synchronizer.addFuture(writeFuture); | |||
} | |||
// 全てのスレッドが完了するまで待機 | |||
synchronizer.waitForFinished(); | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
<u>ファイルの操作を終了する時、一般的に、<code>QFile::unlock</code>メソッドを先に実行して、次に<code>QFile::close</code>メソッドを実行するべきである。</u><br> | |||
* リソースの解放順序 | |||
*: ロックは、ファイルハンドルに関連付けられたリソースである。 | |||
*: ファイルを閉じる前にロックを解除することにより、リソースを適切に解放することができる。 | |||
* 他のプロセスやスレッドへの配慮 | |||
*: ファイルを閉じる前にロックを解除することで、他のプロセスやスレッドがファイルにアクセスできるようになる。 | |||
*: これにより、リソースの効率的な利用が可能になる。 | |||
* エラー処理の簡素化 | |||
*: ロックの解除に失敗した場合、ファイルがまだ開いている状態でエラー処理を行うことができる。 | |||
<br><br> | <br><br> | ||