我想用生產消費模式,多執行緒復制檔案,使用靜態方法 QFile::copy()
執行一半就會崩潰,只復制了一部分。
如果我在 QFile::copy() 下面加一句 qDebug() << "hello"; ,也就是consumer.cpp 第24行,就不會崩潰
QFile::copy(src, dst);
qDebug() << "hello";
這是什么原因呢?
producer.h
struct MoveInfo {
bool rm;
QString src;
QString dst;
};
enum TAG {
COUNT_FILE = 0,
HANDLE = 1,
};
static QSemaphore freeSpace(8); // 控制任務佇列緩沖長度
static QSemaphore usedSpace(0);
static QQueue<MoveInfo> task_q;
class Producer : public QThread
{
Q_OBJECT
public:
Producer(QObject *parent=nullptr);
~Producer();
void run();
void setParams(QString, QString, bool);
signals:
void mainMsgChanged(QString, QColor c=Qt::black);
void subMsgChanged(QString);
void completed();
private:
QString root_path;
int total = 0;
int count = 0;
QString src_path;
QString dst_path;
bool rm;
void walkPath(QString, QString, TAG);
};
producer.cpp
Producer::Producer(QObject *parent)
:QThread (parent)
{
}
void Producer::run()
{
qDebug().noquote() << "Source path:" << src_path;
total = 0;
count = 0;
emit mainMsgChanged(tr("正在統計數量..."));
walkPath(src_path, dst_path, TAG::COUNT_FILE);
qDebug().noquote() << "Total number of files:" << total;
count = 0;
emit mainMsgChanged(tr("正在處理..."));
walkPath(src_path, dst_path, TAG::HANDLE);
emit mainMsgChanged(tr("Ready"));
if(total != 0)
emit subMsgChanged(QString("[%1%] %2/%3").arg(int(100*((float)count/total))).arg(count).arg(total));
else
emit subMsgChanged(QString("[%1%] %2/%3").arg(100).arg(count).arg(total));
// 沒有更多檔案了,放入空資訊通知消費執行緒退出
MoveInfo info;
for (int i = 0; i < 8; i++)
{
freeSpace.acquire();
task_q.enqueue(info);
usedSpace.release();
}
}
void Producer::walkPath(QString src, QString dst, TAG t)
{
QDir src_dir(src);
QDir dst_dir(dst);
QFileInfoList src_files = src_dir.entryInfoList(QStringList{"*.xls"}, QDir::Files | QDir::NoDotAndDotDot);
MoveInfo info;
if (t == TAG::COUNT_FILE)
emit subMsgChanged(QDir::toNativeSeparators(src)); // 通知界面當前目錄
for(auto file : src_files)
{
if(t == TAG::COUNT_FILE) // 先統計檔案總數
{
total++;
} else {
info.rm = rm;
info.src = file.filePath();
info.dst = dst_dir.filePath(file.fileName());
freeSpace.acquire();
task_q.enqueue(info); // 將檔案資訊放入佇列
usedSpace.release();
count++;
//通知界面更新進度
emit subMsgChanged(QString("[%1%] %2/%3").arg(int(100*((float)count/total))).arg(count).arg(total));
}
}
QStringList src_dirs = src_dir.entryList(QStringList{}, QDir::Dirs | QDir::NoDotAndDotDot);
// 遞回處理所有子目錄
for(auto sd : src_dirs)
{
if(!dst_dir.exists(sd) && t == TAG::HANDLE)
dst_dir.mkdir(sd);
walkPath(src_dir.filePath(sd), dst_dir.filePath(sd), t);
}
}
Producer::~Producer()
{
}
consumer.h 消費者
class Consumer : public QThread
{
Q_OBJECT
public:
Consumer(QObject *parent=nullptr);
~Consumer();
void run();
};
consumer.cpp 消費者
Consumer::Consumer(QObject *parent)
: QThread(parent)
{
}
void Consumer::run()
{
MoveInfo info;
qDebug() << currentThreadId();
while (true)
{
usedSpace.acquire();
info = task_q.dequeue(); // 獲取一個檔案資訊
freeSpace.release();
if (info.src.isEmpty()) // 如果檔案名為空,則中斷,結束
break;
if(!QFileInfo::exists(info.dst))
{
QFile::copy(info.src, info.dst);
qDebug() << "hellow world"; // 不加這一句就會崩潰
}
if(info.rm)
QFile::remove(info.src);
}
}
Consumer::~Consumer()
{
}
void MainWindow::start()
{
mProducer.setParams("D:/files", "D:/target/", false);
mProducer->start();
for (int i = 0; i < 8; i++)
{
Consumer *c = new Consumer();
connect(c, &Consumer::finished, c, &Consumer::deleteLater);
c->start();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/172720.html
標籤:Qt
下一篇:【小程式遇到的一個問題】
