• 1478阅读
  • 8回复

多线程调用CopyFileEx拷贝大文件(超过1GB的文件)回调函数100%时,等一分钟左右才返回CopyFileEx的返回值 [复制链接]

上一主题 下一主题
离线lwei24
 

只看楼主 倒序阅读 楼主  发表于: 2021-08-20
各位大佬,请帮帮忙,如下代码,在多线程调用CopyFileEx拷贝大文件(超过1GB的文件)回调函数的拷贝进度值到达100%时,为什么没有立即返回CopyFileEx的返回值,而是等一分钟左右才返回CopyFileEx的返回值,导致了主线程一直在等子线程,出现了界面假死的情况。欢迎各位大佬指点一下,小弟在此不胜感激了!
  1. BOOL bRet = CopyFileEx((LPCWSTR)src,(LPCWSTR)dst, CallBackCopyProgressFunc, this, (LPBOOL)m_bCancel, COPY_FILE_FAIL_IF_EXISTS);
  2.     qWarning()<<"endTime="<<QTime::currentTime().toString("h:m:s");
  3.     qWarning()<<"ret="<<bRet;
  4.     if(!bRet)
  5.     {
  6.         QFile fileTmp(dstPath);
  7.         fileTmp.remove();
  8.         qWarning()<<QString("CopyFile Failed, ErrorCode=%1!").arg(QString::number(GetLastError()));
  9.         return;
  10.     }
  11.     else
  12.     {
  13.         qWarning()<<QString("CopyFile Success!");
  14.     }
  15.     return;


回调函数:
  1. static DWORD CALLBACK CallBackCopyProgressFunc(LARGE_INTEGER totalSize,  LARGE_INTEGER totalTransferred, LARGE_INTEGER streamSize,
  2.                                         LARGE_INTEGER streamTransferred, DWORD streamNo,DWORD callbackReason,HANDLE src,HANDLE dst,LPVOID data)
  3. {
  4.     Q_UNUSED(streamSize) Q_UNUSED(streamTransferred)
  5.             Q_UNUSED(streamNo) Q_UNUSED(callbackReason)
  6.             Q_UNUSED(src) Q_UNUSED(dst)
  7.     static int nRecord = 0;
  8.     nRecord++;
  9.     auto pObject =static_cast<subThread *>(data);
  10.     if(totalSize.QuadPart != 0)
  11.     {
  12.         pObject->m_nCopyValue = totalTransferred.QuadPart*100/totalSize.QuadPart;
  13.         if(pObject->m_nCopyValue != 0 && pObject->m_nCopyValue%50 == 0)
  14.             qWarning()<<QString("emit Number of callbacks:%1,The copy progress of value:%2").arg(QString::number(nRecord)).arg(QString::number(pObject->m_nCopyValue));
  15.         if(pObject->m_nCopyValue > 0)
  16.         {
  17.             emit pObject->sigCopyValue(pObject->m_nCopyValue);
  18.             qApp->processEvents();
  19.             if(pObject->m_nCopyValue == 100)
  20.             {
  21.                 pObject->m_bCancel = TRUE;
  22.             }
  23.         }
  24.     }
  25.     return PROGRESS_CONTINUE;
  26. }









离线hitler++

只看该作者 1楼 发表于: 2021-08-21
如果不是用的固态硬盘,任何涉及磁盘操作用多线程只会导致速度更慢,除非系统已经缓存过数据了,否则多个线程抢占物理磁头,IOPS一共才20多,(100%时还在等待,应该是系统还在flush数据到硬盘)
离线snow_man_0

只看该作者 2楼 发表于: 2021-08-23
可以自己写一个CopyFileEx函数,不用别人的
1条评分好评度+1
hitler++ 好评度 +1 - 2021-08-23
离线lwei24

只看该作者 3楼 发表于: 2021-08-25
回 hitler++ 的帖子
hitler++:如果不是用的固态硬盘,任何涉及磁盘操作用多线程只会导致速度更慢,除非系统已经缓存过数据了,否则多个线程抢占物理磁头,IOPS一共才20多,(100%时还在等待,应该是系统还在flush数据到硬盘)
 (2021-08-21 20:28) 

请问有什么办法可以优化吗?
离线lwei24

只看该作者 4楼 发表于: 2021-08-25
回 snow_man_0 的帖子
snow_man_0:可以自己写一个CopyFileEx函数,不用别人的 (2021-08-23 07:59) 

bool copyFileA(QString &srcPath, QString &dstPath)
{
    QFile file(srcPath);
    qWarning()<<"file size="<<file.size();

    QByteArray s = srcPath.toLatin1();
    char *src = (char*)s.data();

    QByteArray d = dstPath.toLatin1();
    char *dst = (char*)d.data();

    ifstream in(src, ios::binary);
    ofstream ou(dst, ios::binary);

    if(!in.is_open())
    {
        qWarning()<<"src is open failed!";
        emit sigCopyValue(m_nCopyValue);
        return false;
    }

    if(dst == src)
    {
        qWarning()<<"the src file can't be same with dst file";
        emit sigCopyValue(m_nCopyValue);
        return false;
    }

    char buffer[64*1024] = {0};
    long long totalBytes = 0;
    qWarning()<<"hello...";
    //m_mutex2.lock();
    while(in)
    {
        in.read(buffer, 64*1024);
        ou.write(buffer, in.gcount());

        totalBytes += in.gcount();
        m_nCopyValue = (int)((totalBytes*1.0/file.size())*100);
        qWarning()<<"copyValue="<<m_nCopyValue;
        QElapsedTimer et;
        et.start();
        while(et.elapsed() < 25)
        {
            emit sigCopyValue(m_nCopyValue);
            QCoreApplication::processEvents();
        }
        if(totalBytes == file.size())
            break;
    }
    //m_mutex2.unlock();
    in.close();
    ou.close();

    qWarning()<<"fstream close";
    return true;
}

我自己也写了一个类似CopyFileEx的函数,但是在同时启动两个线程去拷贝两个大于1GB的文件时,它直接进入那个循环,然后就不停的发信号,可能是发信号太快了,主线程没有来的及回复,导致了主界面还是会卡顿、假死,请问以上的代码,可以做哪些优化或修改吗?
离线snow_man_0

只看该作者 5楼 发表于: 2021-08-28
回 lwei24 的帖子
lwei24:bool copyFileA(QString &srcPath, QString &dstPath)
{
    QFile file(srcPath);
    qWarning()<<"file size="<<file.size();
....... (2021-08-25 11:20) 

void copyFileA(const QString &srcPath, const QString &dstPath, int* progress)
后面加上进度

把copyFileA放在单独线程里面,在外面监视progress值,就可以了

函数尽量保持独立,不要在函数里面向外发射信号

另外用QFILE就可以,不需要用IOStream
离线lwei24

只看该作者 6楼 发表于: 2021-08-30
回 snow_man_0 的帖子
snow_man_0:void copyFileA(const QString &srcPath, const QString &dstPath, int* progress)
后面加上进度
把copyFileA放在单独线程里面,在外面监视progress值,就可以了
....... (2021-08-28 03:18) 

你说的外面监视,是要声明一个静态的变量progress吗??如果不是在函数里发送信号,又怎么能够实时获取到进度值呢?
离线fsu0413

只看该作者 7楼 发表于: 2021-09-04
我觉得可能就是这样的,因为Windows自带的文件管理器也这样
界面假死的话,看看是不是你的函数并没有跑在子线程
离线lwei24

只看该作者 8楼 发表于: 2021-09-09
回 fsu0413 的帖子
fsu0413:我觉得可能就是这样的,因为Windows自带的文件管理器也这样
界面假死的话,看看是不是你的函数并没有跑在子线程 (2021-09-04 13:05) 

好的,多谢!
快速回复
限100 字节
 
上一个 下一个