Segmentation fault(core dumped) in multi threading in c++ - c++

My code is making me crazy as it sometimes works fine but sometimes get core dumped or segmentation fault or double free(faststop ) error.
I think it's because some threads can not be created but I couldn't make it. What is wrong with this code?
This code is supposed to find \n's in a text file that is stored in path.
Here is the code:
This is Search_inp struct
typedef struct Search_inp{
string * path;
string * phrase;
int a ;
int b;
int file_size;
vector<int>* vec;
}search_inp;
This function should return a void * pointer to the struct that contains my data that I want to pass to thread!
void * make_search_inp(string & path , string & phrase , int a , int b , int file_size , vector<int>&vec){
search_inp * res = (search_inp*)malloc(sizeof(search_inp));
res->path = &path;
res->phrase = & phrase;
res->a = a;
res->b = b;
res -> file_size = file_size;
res->vec = &vec;
return (void *)res;
}
This function will starting the search of \n's in the file
// this function will multi thread the search of \n's and do this through search func
void find_backslash(string path , vector<int> &place_backslash , int file_size){
int counter = 0;
string backslash = "\n";
vector<void*>temp;
vector<pthread_t> tid;
pthread_t t;
while(counter * range <= file_size ){
temp.push_back( make_search_inp(path , backslash , counter*range , (counter+1)*range-1 , file_size , place_backslash ));
pthread_create(&t, NULL , search , temp.back() );
tid.push_back(t);
counter++;
}
for(int i = 0 ; i<tid.size() ;i++) pthread_join(tid[i] , NULL);
//when the erorr happend program can not reach this place...
while(tid.size()) tid.pop_back();
while(temp.size()) temp.pop_back();
sort(place_backslash.begin() , place_backslash.end());
}
This is search function of my code:
void* search(void * temp){
search_inp* Stemp = (search_inp*)temp;
string path = *(Stemp->path);
string phrase = *(Stemp->phrase);
int a = Stemp->a;
int b = Stemp->b;
int file_size = Stemp->file_size;
vector<int>&vec = *(Stemp->vec);
if(path == "" ) return NULL;//check the path correctness
ifstream fin;//1opening the file 2check if the file opening is successful 3put the g in the correct place with seekg
fin.open(path.c_str());
if(a < 0) a=0;
if(b < 0) b=0;
if(a >file_size)
a = b = file_size;
if(b > file_size){
b = file_size;
}
fin.seekg(a , fin.beg);
if(!fin){
cout << "ERROR:File Does Not Exist!" << endl;
return NULL;
}
//opening the output file for
//The search phase
int counter=0 , charNum =a;//this counter hold the number of appearance of the phrase in the file
while(!fin.eof() && charNum < b){
int cnt = 0;char inp;
do{
fin.get(inp);charNum++;
if(phrase[cnt] == inp)
cnt++;
else
break;
}while( cnt<phrase.length() && !fin.eof());
if( cnt == phrase.length()){
counter++;
vec.push_back( ((int)fin.tellg())-1 );
}
}
fin.close();
}
I will run this program calling find_backslah(path_of_my_file , a vector<int> , size_of_file) and get the error sometimes and it isn't happening always.

I'm just guessing at the problem here, but you pass a (pointer to a) structure to all threads, and all threads have some common pointers that they all share in the structure, for example the std::vector. If more than one thread tries to modify the vector at the same time you have a race condition.
Race conditions are bad and you need to protect against them using some kind of lock, for example using a mutex.

Related

How to fix 'Heap has been corrupted 'error in c++?

When I run the program, I get exception "heap has been corrupted" after completion of the function
I have read that this exception may cause if you are using memory that has been freed, or when you are writing to index which is out of array index. But none of the cases applies here. I have read other answers of some problems but it didn't help much.
`char fileNametoExport[26]="d:\\FOlder1\\part1.ipt";
char WorkingFolderName[260] ="d:\\folder";
int start = rFind(fileNametoExport, '\\');
int finish = rFind(fileNametoExport, '.');
if (start == -1)
start = 0;
char partname[260];
strcpy(partname,substr(fileNametoExport, start, finish));
::AfxMessageBox((LPCTSTR)partname);
char xtfile[260];
char xmltxtfile[260];
strcpy(xtfile, strcat(WorkingFolderName, partname));
strcat(xtfile, "__Default.x_t");
strcpy(xmltxtfile, WorkingFolderName);
strcat(xmltxtfile,"_XT_SE_INV_Default_SOLID_0_Solid1_xt.xmt_txt");`
function rfind() to find occurence of char in char array-
int rFind(char* s, char c)
{
int sz = 0;
char *tmp = s;
while (*tmp != '\0')
{
sz++;
tmp++;
}
for (int i = sz - 1; i >= 0; i--)
{
if (*(s + i) == c)
return i;
}
return -1;
}
function substr() to get substring from position x to y (y exclusive)
char* substr(char* s, const int b, const int f)
{
char *str = new char[f - b];
int t = 0;
for (int i = b; i != f; i++)
{
str[t] = s[i];
t++;
}
str[t] = '\0';
return str;
}
P.S- While giving input I ensure that fileNametoExport always contains '.' and '\'.
Your program do not check lengths of input strings. You can receive a string longer than your buffer and program will fail.
If your program get fileNametoExport = "d:\\somefolder\\somefilewithoutdot" , finish will be -1 and program fail at strcpy(partname,substr(fileNametoExport, start, finish)); .
Program writes after buffer in char* substr(char* s, const int b, const int f) at line
str[t] = '\0';
because t at this point equal f-b , size of str buffer.
Function _ASSERTE( _CrtCheckMemory( ) ); from <crtdbg.h> very useful when searching for bugs like this. Put it around suspicious code and it fails after your bug. It works only in debug.

How scan two strings separated by `/` using sscanf?

I want to scan to separate strings separated by a / using sscanf but it doesn't work. It works fine with a space.
For example, I want to separate the string 50%/60% into two strings like 50% and 60%.
You can have a look at code here:
#include <iostream>
using namespace std;
int extract_break_rewrites(int *m, int *n, const char *arg)
{
char m_str[10];
char n_str[10];
int err;
int count = sscanf(arg, "%s %s", n_str, m_str);
printf("%s %s %d\n",n_str, m_str,count);
if (count == 0) {
count = sscanf(arg, "/%s", m_str);
if (count == 0) {
*m = 0;
*n = 0;
return -1;
}
if (sscanf(m_str, "%d%%", m) != 1)
return -1;
}
else if (count == 1) {
if (sscanf(n_str, "%d%%", n) != 1)
return -1;
}
else if (count==2) {
if (sscanf(n_str, "%d%%", n) != 1)
return -1;
if (sscanf(m_str, "%d%%", m) != 1)
return -1;
}
return 1;
}
int main() {
int n,m;
const char * command = "50% 60%";
if (extract_break_rewrites(&m,&n,command)!=-1)
cout<<"Successful. The values of m and n are "<<m<<" and "<<n<<", respectively.\n";
else
cout<<"There was error in processing, may be input was not in the correct format.\n";
return 0;
}
You don't need to worry about what the code does, the important lines are 10, 11 and main function.
Try the following (assuming from stdin):
scanf("%[^/]/%s");
Use sscanf(buf, ...); if reading from a buffer.
The issue is that %s for scanf assumes that the string is followed by a space. This approach instructs scanf to find a string delimited by /, and then match the rest as a separate string.
EDIT: accidentally dropped the / in the scan string
Use a scan set
char a[100];
char b[100];
scanf("%[^/]/%s", a, b);
This scans in everything until it gets a /, then it starts and reads in a string.
You can also use std::strings and their facilities to achieve the same result:
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::stoi;
bool extract_break_rewrites(int &m, int &n, const string &arg) {
// find position of %/ in the string
string::size_type pos_first = arg.find("%/");
// check if the return value is valid (the substring is present and there
// is something else first)
if ( pos_first == string::npos || !pos_first ) // wrong input
return false;
string::size_type pos_2 = pos_first + 2,
pos_last = arg.find("%", pos_2);
if ( pos_last == string::npos || pos_last == pos_2 )
return false;
try {
m = stoi(arg.substr(0, pos_first));
n = stoi(arg.substr(pos_2, pos_last - pos_2));
}
// invalid argument or out of range
catch (...) {
return false;
}
return true;
}
int main() {
int n = 0, m = 0;
string command = "150%/60%";
if ( extract_break_rewrites(m, n, command) )
cout << "Successful. The values of m and n are "
<< m << " and " << n << ", respectively.\n";
else
cout << "There was error in processing, "
<< "maybe input was not in the correct format.\n";
return 0;
}

Stack going out of scope. Maybe not calling it correctly?

The issue I am having is with my vector going out of scope. Both the constructor and the other method are being called in the main one right after another but the problem is that after the constructor runs the vector goes out of scope. Anyone have any thoughts on how to fix this? I thought i fixed it but just made things worse.
header:
struct input
{
bool dirtyBit;
int statusBit; //0 not in cache, 1 in cache, 2 in 2nd cache
bool writeStatus; //write = 1 read = 0
int address;
int indivBlockIndex;
int indivBlockOffset;
};
class Cache
{
public:
vector<input > dataBase;
Cache(string);
~Cache();
void DirectMapped(int, int);
};
implementation:
Cache::Cache(string infile)
{
ifstream in(infile);
string readWriteStatus;
int Addr;
while (in >> readWriteStatus >> hex >> Addr)
{
input contents;
//contents = new input;
if (readWriteStatus == "read")
contents.writeStatus = true;
else if (readWriteStatus == "write")
contents.writeStatus = false;
contents.address = Addr;
contents.dirtyBit = false;
contents.statusBit = 0;
contents.indivBlockIndex = -1;
contents.indivBlockOffset = -1;
dataBase.push_back(contents);
}
}
Cache::~Cache(){}
void Cache::DirectMapped(int cacheSize, int blockSize)
{
//initial stats needed
int blockCount = cacheSize/blockSize; //number of total blocks
//clear out the cache
for (int i = 0; i < dataBase.size(); i++)
dataBase[i].statusBit = 0;
//other stuff not related to question
}
main:
int main(int argc, char *argv[])
{
//string in = argv[1];
string inputfile = "C:/Users/Christopher/Downloads/testprac";
string infile = inputfile.append(".trace");
Cache myCache(infile);
// Parse Command Line Argument
// if(argc != 2)
// cout << "ERROR: Improper Number of Arguments" << endl;
// else
// {
int i = 1024, j = 8;
myCache.DirectMapped(i,j);
system ( "pause");
return 0;
}
The main makes a call directly from myCache(infile) to myCache.DirectMapped(i,j) in two consecutive lines.
Thanks for your help guys. I really appreciate it.
"Before the first line" of a function is one point where debuggers frequently aren't able to display the correct values of anything (because things haven't been set up).
It's actually more likely that the vector isn't in scope yet.
Step into the function before drawing any conclusions.

reading last n lines from file in c/c++

I have seen many posts but didn't find something like i want.
I am getting wrong output :
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ...... // may be this is EOF character
Going into infinite loop.
My algorithm:
Go to end of file.
decrease position of pointer by 1 and read character by
character.
exit if we found our 10 lines or we reach beginning of file.
now i will scan the full file till EOF and print them //not implemented in code.
code:
#include<iostream>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
int main()
{
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
int i,j,pos;
int count=0;
char ch;
int begin=ftell(f1);
// GO TO END OF FILE
fseek(f1,0,SEEK_END);
int end = ftell(f1);
pos=ftell(f1);
while(count<10)
{
pos=ftell(f1);
// FILE IS LESS THAN 10 LINES
if(pos<begin)
break;
ch=fgetc(f1);
if(ch=='\n')
count++;
fputc(ch,f2);
fseek(f1,pos-1,end);
}
return 0;
}
UPD 1:
changed code: it has just 1 error now - if input has lines like
3enil
2enil
1enil
it prints 10 lines only
line1
line2
line3ÿine1
line2
line3ÿine1
line2
line3ÿine1
line2
line3ÿine1
line2
PS:
1. working on windows in notepad++
this is not homework
also i want to do it without using any more memory or use of STL.
i am practicing to improve my basic knowledge so please don't post about any functions (like tail -5 tc.)
please help to improve my code.
Comments in the code
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *in, *out;
int count = 0;
long int pos;
char s[100];
in = fopen("input.txt", "r");
/* always check return of fopen */
if (in == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
out = fopen("output.txt", "w");
if (out == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
fseek(in, 0, SEEK_END);
pos = ftell(in);
/* Don't write each char on output.txt, just search for '\n' */
while (pos) {
fseek(in, --pos, SEEK_SET); /* seek from begin */
if (fgetc(in) == '\n') {
if (count++ == 10) break;
}
}
/* Write line by line, is faster than fputc for each char */
while (fgets(s, sizeof(s), in) != NULL) {
fprintf(out, "%s", s);
}
fclose(in);
fclose(out);
return 0;
}
There are a number of problems with your code. The most
important one is that you never check that any of the functions
succeeded. And saving the results an ftell in an int isn't
a very good idea either. Then there's the test pos < begin;
this can only occur if there was an error. And the fact that
you're putting the results of fgetc in a char (which results
in a loss of information). And the fact that the first read you
do is at the end of file, so will fail (and once a stream enters
an error state, it stays there). And the fact that you can't
reliably do arithmetic on the values returned by ftell (except
under Unix) if the file was opened in text mode.
Oh, and there is no "EOF character"; 'ÿ' is a perfectly valid
character (0xFF in Latin-1). Once you assign the return value
of fgetc to a char, you've lost any possibility to test for
end of file.
I might add that reading backwards one character at a time is
extremely inefficient. The usual solution would be to allocate
a sufficiently large buffer, then count the '\n' in it.
EDIT:
Just a quick bit of code to give the idea:
std::string
getLastLines( std::string const& filename, int lineCount )
{
size_t const granularity = 100 * lineCount;
std::ifstream source( filename.c_str(), std::ios_base::binary );
source.seekg( 0, std::ios_base::end );
size_t size = static_cast<size_t>( source.tellg() );
std::vector<char> buffer;
int newlineCount = 0;
while ( source
&& buffer.size() != size
&& newlineCount < lineCount ) {
buffer.resize( std::min( buffer.size() + granularity, size ) );
source.seekg( -static_cast<std::streamoff>( buffer.size() ),
std::ios_base::end );
source.read( buffer.data(), buffer.size() );
newlineCount = std::count( buffer.begin(), buffer.end(), '\n');
}
std::vector<char>::iterator start = buffer.begin();
while ( newlineCount > lineCount ) {
start = std::find( start, buffer.end(), '\n' ) + 1;
-- newlineCount;
}
std::vector<char>::iterator end = remove( start, buffer.end(), '\r' );
return std::string( start, end );
}
This is a bit weak in the error handling; in particular, you
probably want to distinguish the between the inability to open
a file and any other errors. (No other errors should occur,
but you never know.)
Also, this is purely Windows, and it supposes that the actual
file contains pure text, and doesn't contain any '\r' that
aren't part of a CRLF. (For Unix, just drop the next to the
last line.)
This can be done using circular array very efficiently.
No additional buffer is required.
void printlast_n_lines(char* fileName, int n){
const int k = n;
ifstream file(fileName);
string l[k];
int size = 0 ;
while(file.good()){
getline(file, l[size%k]); //this is just circular array
cout << l[size%k] << '\n';
size++;
}
//start of circular array & size of it
int start = size > k ? (size%k) : 0 ; //this get the start of last k lines
int count = min(k, size); // no of lines to print
for(int i = 0; i< count ; i++){
cout << l[(start+i)%k] << '\n' ; // start from in between and print from start due to remainder till all counts are covered
}
}
Please provide feedback.
int end = ftell(f1);
pos=ftell(f1);
this tells you the last point at file, so EOF.
When you read, you get the EOF error, and the ppointer wants to move 1 space forward...
So, i recomend decreasing the current position by one.
Or put the fseek(f1, -2,SEEK_CUR) at the beginning of the while loop to make up for the fread by 1 point and go 1 point back...
I believe, you are using fseek wrong. Check man fseek on the Google.
Try this:
fseek(f1, -2, SEEK_CUR);
//1 to neutrialize change from fgect
//and 1 to move backward
Also you should set position at the beginning to the last element:
fseek(f1, -1, SEEK_END).
You don't need end variable.
You should check return values of all functions (fgetc, fseek and ftell). It is good practise. I don't know if this code will work with empty files or sth similar.
Use :fseek(f1,-2,SEEK_CUR);to back
I write this code ,It can work ,you can try:
#include "stdio.h"
int main()
{
int count = 0;
char * fileName = "count.c";
char * outFileName = "out11.txt";
FILE * fpIn;
FILE * fpOut;
if((fpIn = fopen(fileName,"r")) == NULL )
printf(" file %s open error\n",fileName);
if((fpOut = fopen(outFileName,"w")) == NULL )
printf(" file %s open error\n",outFileName);
fseek(fpIn,0,SEEK_END);
while(count < 10)
{
fseek(fpIn,-2,SEEK_CUR);
if(ftell(fpIn)<0L)
break;
char now = fgetc(fpIn);
printf("%c",now);
fputc(now,fpOut);
if(now == '\n')
++count;
}
fclose(fpIn);
fclose(fpOut);
}
I would use two streams to print last n lines of the file:
This runs in O(lines) runtime and O(lines) space.
#include<bits/stdc++.h>
using namespace std;
int main(){
// read last n lines of a file
ifstream f("file.in");
ifstream g("file.in");
// move f stream n lines down.
int n;
cin >> n;
string line;
for(int i=0; i<k; ++i) getline(f,line);
// move f and g stream at the same pace.
for(; getline(f,line); ){
getline(g, line);
}
// g now has to go the last n lines.
for(; getline(g,line); )
cout << line << endl;
}
A solution with a O(lines) runtime and O(N) space is using a queue:
ifstream fin("file.in");
int k;
cin >> k;
queue<string> Q;
string line;
for(; getline(fin, line); ){
if(Q.size() == k){
Q.pop();
}
Q.push(line);
}
while(!Q.empty()){
cout << Q.front() << endl;
Q.pop();
}
Here is the solution in C++.
#include <iostream>
#include <string>
#include <exception>
#include <cstdlib>
int main(int argc, char *argv[])
{
auto& file = std::cin;
int n = 5;
if (argc > 1) {
try {
n = std::stoi(argv[1]);
} catch (std::exception& e) {
std::cout << "Error: argument must be an int" << std::endl;
std::exit(EXIT_FAILURE);
}
}
file.seekg(0, file.end);
n = n + 1; // Add one so the loop stops at the newline above
while (file.tellg() != 0 && n) {
file.seekg(-1, file.cur);
if (file.peek() == '\n')
n--;
}
if (file.peek() == '\n') // If we stop in the middle we will be at a newline
file.seekg(1, file.cur);
std::string line;
while (std::getline(file, line))
std::cout << line << std::endl;
std::exit(EXIT_SUCCESS);
}
Build:
$ g++ <SOURCE_NAME> -o last_n_lines
Run:
$ ./last_n_lines 10 < <SOME_FILE>

C++ fstream outputs wrong data

Context first:
My program do some parallel calculation which are logged in a file. Threads are grouped by blocks (I'm using CUDA). The log file is formated this way:
#begin run
({blockIdx,threadIdx}) {thread_info}
({blockIdx,threadIdx}) {thread_info}
...
#end run
I've wrote a function that should read the log file and sort each run messages by thread.
//------------------------------------------------------------------------------
// Comparison struct for log file sorting
//------------------------------------------------------------------------------
typedef struct
{
bool operator()(const string &rString1 , const string &rString2)
{
int closeParenthesisLocalition1 = rString1.find_first_of(')');
int closeParenthesisLocalition2 = rString2.find_first_of(')');
int compResult = rString1.compare(0 , closeParenthesisLocalition1 + 2 , rString2 , 0 , closeParenthesisLocalition2 + 2);
return (compResult < 0);
}
} comp;
//------------------------------------------------------------------------------------
// Sort the log file. Lines with same prefix (blockIdx,ThreadIdx) will be grouped in file per run.
//------------------------------------------------------------------------------------
void CudaUnitTest::sortFile()
{
comp comparison;
deque<string> threadsPrintfs;
ifstream inputFile(m_strInputFile);
assert(inputFile.is_open());
//Read whole input file and close it. Saves disk accesses.
string strContent((std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>());
inputFile.close();
ofstream outputFile(m_strOutputFile);
assert(outputFile.is_open());
string strLine;
int iBeginRunIdx = -10; //value just to addapt on while loop (to start on [0])
int iBeginRunNewLineOffset = 10; //"idx offset to a new line char in string. Starts with the offset of the string "#begin run\n".
int iEndRunIdx;
int iLastNewLineIdx;
int iNewLineIdx;
while((iBeginRunIdx = strContent.find("#begin run\n" , iBeginRunIdx + iBeginRunNewLineOffset)) != string::npos)
{
iEndRunIdx = strContent.find("#end run\n" , iBeginRunIdx + iBeginRunNewLineOffset);
assert(iEndRunIdx != string::npos);
iLastNewLineIdx = iBeginRunIdx + iBeginRunNewLineOffset;
while((iNewLineIdx = strContent.find("\n" , iLastNewLineIdx + 1)) < iEndRunIdx)
{
strLine = strContent.substr(iLastNewLineIdx + 1 , iNewLineIdx);
if(verifyPrefix(strLine))
threadsPrintfs.push_back(strLine);
iLastNewLineIdx = iNewLineIdx;
}
//sort last run info
sort(threadsPrintfs.begin() , threadsPrintfs.end() , comparison);
threadsPrintfs.push_front("#begin run\n");
threadsPrintfs.push_back("#end run\n");
//output it
for(deque<string>::iterator it = threadsPrintfs.begin() ; it != threadsPrintfs.end() ; ++it)
{
assert(outputFile.good());
outputFile.write(it->c_str() , it->size());
}
outputFile.flush();
threadsPrintfs.clear();
}
outputFile.close();
}
The problem is that the resulting file has a lot of trash data. For example an input log file with 6KB generated a output log of 192KB! It appears the output file has a lot of repetitions of the input file. When debugging code the deque showed the right values before and after sort, though. I think there is something wrong with the ofstream write itself.
Edit: The function isn't running in parallel.
Just to show the final code. Note the change on substr, now instead of an index it's receiving the lenght.
//------------------------------------------------------------------------------------
// Sort the log file. Lines with same prefix (blockIdx,ThreadIdx) will be grouped in file per run.
//------------------------------------------------------------------------------------
void CudaUnitTest::sortFile()
{
comp comparison;
deque<string> threadsPrintfs;
ifstream inputFile(m_strInputFile);
assert(inputFile.is_open());
//Read whole input file and close it. Saves disk accesses.
string strContent((std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>());
inputFile.close();
ofstream outputFile(m_strOutputFile);
assert(outputFile.is_open());
string strLine;
int iBeginRunIdx = -10; //value just to addapt on while loop (to start on [0])
int iBeginRunNewLineOffset = 10; //"idx offset to a new line char in string. Starts with the offset of the string "#begin run\n".
int iEndRunIdx;
int iLastNewLineIdx;
int iNewLineIdx;
while((iBeginRunIdx = strContent.find("#begin run\n" , iBeginRunIdx + iBeginRunNewLineOffset)) != string::npos)
{
iEndRunIdx = strContent.find("#end run\n" , iBeginRunIdx + iBeginRunNewLineOffset);
assert(iEndRunIdx != string::npos);
iLastNewLineIdx = iBeginRunIdx + iBeginRunNewLineOffset;
while((iNewLineIdx = strContent.find("\n" , iLastNewLineIdx + 1)) < iEndRunIdx)
{
strLine = strContent.substr(iLastNewLineIdx + 1 , iNewLineIdx - iLastNewLineIdx);
if(verifyPrefix(strLine))
threadsPrintfs.push_back(strLine);
iLastNewLineIdx = iNewLineIdx;
}
//sort last run info
sort(threadsPrintfs.begin() , threadsPrintfs.end() , comparison);
threadsPrintfs.push_front("#begin run\n");
threadsPrintfs.push_back("#end run\n");
//output it
for(deque<string>::iterator it = threadsPrintfs.begin() ; it != threadsPrintfs.end() ; ++it)
{
assert(outputFile.good());
outputFile.write(it->c_str() , it->size());
}
threadsPrintfs.clear();
}
outputFile.close();
}