C ++: Как прочитать двоичный файл в потоке и записать его в другом потоке? - PullRequest
0 голосов
/ 06 июля 2019

Я хочу прочитать двоичный файл в потоке и записать его в другом потоке. Он работает с небольшими файлами (например, txt-файлом), но не с большими файлами (например, jpg-файлом). Я пытаюсь сохранить буфер в векторе, но он работает как очередь.

#include <iostream>
#include <thread>
#include <queue>
#include <fstream>
#include <unistd.h>
#include <mutex>
#include <string>
using namespace std;

std::mutex mtx;

vector<char *> q;
const int MAX_QUEUE_LENGTH = 100;
int string_size(char * str)
{
    int Size = 0;
    while (str[Size] != '\0') Size++;
    return Size;
}

void readFile()
{
  ifstream file;
  file.open("in.jpg", ios::binary);
  file.seekg(0, ios::end);
  int length = file.tellg();
  cout << length;
  file.seekg(0, ios::beg);

  while (true) {
    mtx.lock();

    if (q.size() > MAX_QUEUE_LENGTH) {
      mtx.unlock();
      sleep(10);
      continue;

    }

    if (length - file.tellg() <= 1024) {
      int tmp = length - file.tellg();
      char *c = new char[tmp];
      file.read(c,tmp);
      q.push_back(c);
      mtx.unlock();
      break;
    } else {
      char *c = new char[1024];
      file.read(c,1024);
      q.push_back(c);
      mtx.unlock();
    } 

  }

  file.close();
}

void writeFile() {
  ofstream o;
  o.open("out.jpg", ios::binary);

  while (true) {
    mtx.lock();
    if(q.empty()) {
      mtx.unlock();
      sleep(5); 
      mtx.lock();
    }

    if(q.empty()) break;
    o.write(q.front(), string_size(q.front()));
    q.erase(q.begin());
    mtx.unlock();
  }

  o.close();
}
int main() {
  thread th_in(readFile);
  thread th_out(writeFile);
  th_in.join();
  th_out.join();
}

Ответы [ 2 ]

0 голосов
/ 06 июля 2019

Основная проблема в функции writeFile, где вызывается string_size.Почему вы предполагаете, что в потоке JPG не может появиться нулевой байт?Предположим, что вы читаете первый блок - 1024 байта, который имеет значение 0 в 10-й позиции, блок ставится в очередь в q, затем во время записи вы вызываете string_size, который возвращает 10, а оставшаяся часть этого блока не записывается в файл -и никогда не будет записан, потому что erase вызывается на q.

. Вы можете сохранить pair с указателем на данные блока и его длину:

vector< std::pair< char *, int> > q;

, затем в readFile:

if (length - file.tellg() <= 1024) {
  int tmp = length - file.tellg();
  char *c = new char[tmp];
  file.read(c,tmp);
  q.emplace_back(c,tmp); // <--- added
  mtx.unlock();
  break;
} else {
  char *c = new char[1024];
  file.read(c,1024);
  q.emplace_back(c,1024); // <--- added
  mtx.unlock();
}

и в writeFile:

if(q.empty()) { mtx.unlock(); break; } // in this place unlock should also be called
o.write(q.front().first, q.front().second); // <--added
q.erase(q.begin());

также вместо хранения необработанного указателя в q рассмотрите возможность использования интеллектуального указателя, например unique_ptr.

0 голосов
/ 06 июля 2019

Посмотрите на этот фрагмент вашего кода:

while (true) {
    mtx.lock();

    if (q.size() > MAX_QUEUE_LENGTH) {
      mtx.unlock();
      sleep(5);
      mtx.lock();
      continue;
    }
....
}

Если if верно, вы блокируете мьютекс дважды , один перед continue, а затем в началеблока while.

Документ mutex сообщает, что это неопределенное поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...