multithreaded file copying - c++

I wrote a c++ code to multithreaded copying a file to another directory in linux. but doesn't work(just it made an empty file in directory).
I don't know what's the problem? I think my tread has no right access to write in the shared file. but don't know what should I do.
It should work when typed in terminal :
$./a.out <file name> <dir> <thread number (default 4)>
This is my code:
/*Multithreads file copier*/
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/sendfile.h>
#include <unistd.h>
#include <cstdio>
char* file;
char* fileout_path;
int fin, fout;
// part of each thread
struct PART{
off_t* offset =0;
size_t size;
};
//multithreading
void *Copy (void * data)
{
struct PART *mypart;
mypart = (struct PART *) data;
//open file to read and write
fin = open(file, O_RDONLY,0);
fout = open(fileout_path, O_WRONLY|O_CREAT, 0644);
unsigned long a = static_cast<unsigned long>(mypart->size);
lseek(fout, a, SEEK_SET); //set offset by size of the part
//use sendfile instead read and write to easier code
sendfile(fin, fout, mypart->offset, mypart->size);
printf("threading....\n");//to know the thread ran
pthread_exit(0);
}
int main(int argc, char *argv[])
{
int threads_number;
if (argv[3]!= NULL)
{
threads_number = atoi(argv[3]);
}
else
{
threads_number = 4;//default thread number
}
//multithreading datatypes
pthread_t tid[threads_number];
pthread_attr_t attr;
pthread_attr_init(&attr);
struct stat f_stat;
struct PART part[threads_number];
//allocation size of each part
unsigned long part_size = f_stat.st_size / threads_number;
for(int i =0; i <number_threads; i++)
{
if ( i == threads_number -1)
{
part[threads_number].size = f_stat.st_size - (part_size * (threads_number -1));
}
else
{
part[i].size = part_size;
}
}
file = argv[1];
stat(file, &f_stat);
fileout_path = argv[2];
int fin1 = open(file, O_RDONLY,0);
int fout1 = open(fileout_path, O_WRONLY|O_CREAT, 0644);
for (int j = 0; j < threads_number; j++)
{
pthread_create(&tid[j], NULL, Copy, (void *)&part[j]);
pthread_join(tid[j],NULL);
}
printf("thread is done.\n");
close(fout);
close(fin);
return 0;
}

Related

How to use mmap for integer input?

I have coded a program that uses mmap as input to fill a integer 2D vector from a .txt file. The code is part of a larger program and will be submitted to a competition. Is there a way to improve the speed using mmap, or by using a different way all together? Here is the code:
#include <fstream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <iostream>
// for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
const char* map_file(const char* fname, size_t& length);
int main()
{
auto start = std::chrono::high_resolution_clock::now();
size_t length;
auto f = map_file("erasmus.in", length);
auto l = f + length;
int i = 0;
bool flag = false;
string lines;
vector<vector<int> > students(10000); //The number of lines is predefined
const char* temp;
while (f && f!=l) {
string element = "";
temp = static_cast<const char*>(memchr(f, '\n', l-f));
for(f = f; f<=temp; f++)
{
if(!isspace(*f))
{
element += *f;
flag = true;
}
if(isspace(*f) && flag == true)
{
flag = false;
int assigned_element = stoi(element);
students[i].push_back(assigned_element);
element = "";
}
}
i++;
temp++;
}
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed1 = finish - start;
FILE* output = fopen("erasmus.out", "w");
for (int i = 0; i < students.size(); i++)
{
for (int j = 0; j < students[i].size(); j++)
{
fprintf(output, "%d ", students[i][j]);
}
fprintf(output, "\n");
}
std::cout << "Elapsed time: " << elapsed1.count() << " s\n";
return 0;
}
void handle_error(const char* msg) {
perror(msg);
exit(255);
}
const char* map_file(const char* directory, size_t& length)
{
int fileDirectory = open(directory, O_RDONLY);
if (fileDirectory == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fileDirectory, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char* map = static_cast<const char*>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fileDirectory, 0u));
if (map == MAP_FAILED)
handle_error("mmap");
return map;
}
The file will be executed on a linux system, if this helps to find the optimal answer. At the end of each line of the .txt
there is a space character (' ') and a newline('\n')

I want, How to read dlt binary File without dlt viwer, using c++ fstream

I want to make simple console program.
the program is dead checking program
Sometimes the point of death on the log is different from where it actually happened.
The format of the dlt file is as follows.
I want to parse the following binary files through c ++.
I tried many times to read the binary file but it failed.
I would appreciate it if you could upload a simple example source.\
Thank you
#include <stdio.h>
#include <fstream>
#include <iterator>
#include <algorithm>
#include <io.h>
#include <vector>
#include <string>
#include <conio.h>
using namespace std;
struct dltLogFormat
{
char dltPattern[100];
unsigned int TimeStamp_sec;
int TimeStamp_mic;
char ECU_ID[4];
};
void main()
{
FILE *fp;
vector<string> dltList;
char dltPattern[5] = "";
unsigned int TimeStamp_sec = 0;
int TimeStamp_mic = 0;
char ECU_ID_CHARACTER[5] = "";
char infoHeader;
unsigned short messageLength;
int ECU_ID = 0;
unsigned int sessionID = 0;
int extHeaderInfo = 0;
unsigned int numberOfArguments = 0;
unsigned int applicationID = 0;
unsigned int ContextID = 0;
char payload[17];
_finddata_t fd;
long handle;
int result = 1;
handle = _findfirst(".\\*.dlt", &fd);
if (handle == -1)
{
printf("There were no dlt files.\n");
return;
}
while (result != -1)
{
dltLogFormat dltFormant;
dltList.push_back(fd.name);
printf("File: %s\n", fd.name);
result = _findnext(handle, &fd);
std::ifstream input(fd.name, std::ios::binary | std::ios::in);
while (true)
{
input >> dltPattern;
input.read((char*)&TimeStamp_sec, sizeof(unsigned int));
input.read((char*)&TimeStamp_mic, sizeof(int));
input >> ECU_ID_CHARACTER;
input.read((char*)&infoHeader, sizeof(char));
input.read((char*)&messageLength, sizeof(unsigned short));
input.read((char*)&ECU_ID, sizeof(int));
input.read((char*)&sessionID, sizeof(unsigned int));
input.read((char*)&extHeaderInfo, sizeof(unsigned int));
input.read((char*)&numberOfArguments, sizeof(unsigned int));
input.read((char*)&applicationID, sizeof(unsigned int));
input.read((char*)&ContextID, sizeof(unsigned int));
input.read(payload, sizeof(char)*messageLength);
//header
//input
//extend header
//payload
}
}
}

Segmentation fault (core dumped), storing char * to string vector of struct

#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <vector>
#include <sstream>
#define SHMSIZE 1024
using namespace std;
namespace patch
{
template < typename T > std::string to_string( const T& n )
{
std::ostringstream stm ;
stm << n ;
return stm.str() ;
}
}
struct process
{
int r;
string name;
vector<string> lines;
};
int main(int argc, char * argv[])
{
int firstRun = 1; //Skipping First Line of Assign-1.ip.
int quantum = 0; //For taking input of quantum.
int count = 0; //For number of processes.
int pchtoint;
string c;
char * pch; //For tokenization.
string reading_file; //Reading a line from file.
char * readarr; //Converting "reading_file" to readarr for tokenization.
process * p;
//=== Quantum Input ===//
cout<<"Enter Quantum size [1-1000]: ";
cin>>quantum;
while(quantum < 1 || quantum > 1000)
{
cout<<"Wrong input!!! Enter Again [1-1000]: ";
cin>>quantum;
}
//=====================//
//===Filing===//
ifstream read("Assign-2.ip");
if(read.is_open())
{
while(!read.eof())
{
getline(read, reading_file);
readarr = new char[reading_file.size() + 1];
for(int i = 0; i < reading_file.length(); i++)
{
readarr[i] = reading_file[i];
}
if(firstRun > 1)
{
int countingline = 0; //counting the number of lines in a process.
pch = strtok (readarr," ,");
while (pch != NULL)
{
c = pch[1];
pchtoint = atoi(c.c_str());
p[pchtoint-1].r++;
p[pchtoint-1].lines.push_back(pch);
for(int i = 0; i < p[pchtoint-1].lines.size(); i++)
cout<<p[pchtoint-1].name<<"=="<<p[pchtoint-1].lines.at(i)<<endl;
pch = strtok (NULL, " ,");
}
}
else
{
pch = strtok (readarr,",.-");
while (pch != NULL)
{
count++;
pch = strtok (NULL, ",.-");
}
p = new process[count];
string s = "p";
for(int i = 0; i < count; i++)
{
s = s + patch::to_string(i+1);
p[i].name = s;
s = s[0];
}
firstRun++;
}
}
}
else
{
cout<<"Cannot open file!!!"<<endl;
}
read.close();
return 0;
}
Enter Quantum size [1-1000]: 2
p1==p1-l1
p2==p2-l1
p3==p3-l1
p1==p1-l1
p1==p1-l2
p2==p2-l1
p2==p2-l2
p3==p3-l1
p3==p3-l2
p1==p1-l1
p1==p1-l2
p1==p1-l3
p3==p3-l1
p3==p3-l2
p3==p3-l3
p1==p1-l1
p1==p1-l2
p1==p1-l3
p1==p1-l4
Segmentation fault (core dumped)
I am reading data from a cvs file. and storing it in struct that is p here. but I don't know why it is giving segmentation fault. I am compiling it on ubuntu terminal.
The input file contains data:
P1, P2, P3,
p1-l1, p2-l1, p3-l1
p1-l2, p2-l2, p3-l2
p1-l3, , p3-l3
p1-l4, ,

Unix file descriptor

Today I found very interesting behavior of file descriptors in Linux. Look at that code:
#include <dirent.h> /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <errno.h>
#define handle_error(msg) \
do { trace(msg); exit(0); } while (0)
#define trace printf
int createFile(const char* name) {
int r;
r = ::open( name, 0 );
if (r < 0)
{
trace("create file : %s\n", name);
r = ::open( name, O_CREAT, 0666 );
if (r < 0)
trace("error r < 0 %d\n",errno);
}
return r;
}
int createDir(const char* name) {
int r = ::mkdir( name, 0777 );
if (r != 0) {
trace("error r!=0\n");
}
r = open(name, 0);
if (r < 0) {
trace("error create dir r <0\n");
}
return r;
}
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
#include <sys/types.h>
#include <dirent.h>
void test123(int fd) {
int nread;
char buf[1024];
unsigned char buffer[1024];
struct linux_dirent *d;
int bpos,r;
char d_type;
if (fd == -1)
handle_error("open");
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, 1024);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
trace("--------------- nread=%d ---------------\n", nread);
trace("i-node# file type d_reclen d_off d_name\n");
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
trace("%8ld ", d->d_ino);
d_type = *(buf + bpos + d->d_reclen - 1);
trace("%4d %10lld %s\n", d->d_reclen,
(long long) d->d_off, d->d_name);
bpos += d->d_reclen;
}
}
}
int main(int argc, const char * argv[]) {
int dir = createDir("test");
int file = createFile("test/file.gg");
test123(dir);
close(dir);
close(file);
return 0;
}
in that code I create folder, save its file descriptor, create file in that folder and after I want to print all files in that directory via file descriptors. However I get this output:
create file : test/file.gg
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
48879 16 1 .
48880 16 2 ..
There is no file.gg file in that folder. So, my question is - how it can be and how to work correctly with file descriptors? As I understand file descriptor is just an index in local for process table with all opened files and directories. But it is looks like that folder descriptor caches somehow files in that folder.
How to work correctly with descriptors in my case?
Try to do an fsync on your directory. You should open directory with O_RDONLY flags. O_WRONLY will fail. Create a file and sync may not sync metadata for this file. More informations in this article

Process terminates when function is called

I'm trying to write a function that will read and print the contents of a file. I gave the filename as a parameter for my function. I used FILE *testfile to create a file handle and then I use fread to read the file. block_t is a struct and nreserved are the reserved segments of the block. Each block has records. I don't think that it is necessary to tell you how block_t is created.
My problem is that even though the function runs and I can see in the console the results that I want to see the process terminates. This happens even if I comment out the if else parts. I get this message Process terminated with status -1073741510
Here is my code:
#include "dbtproj.h"
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
void showEntriesOfBlock(char *filename){
FILE *testfile;
block_t block;
int nreserved;
//open file and print contents
testfile = fopen(filename,"r");
if(testfile==NULL)
cout << "Error";
else{
while(!feof(testfile)){
fread(&block, 1, sizeof(block_t), testfile);
nreserved = block.nreserved;
//print block contents
for (int i=0; i<nreserved; ++i) {
printf("this is block id: %d, record id: %d, num: %d, str: %s\n",
block.blockid, block.entries[i].recid, block.entries[i].num,
block.entries[i].str);
}
}
}
fclose(testfile);
};
In my main file I create a file by using outfile = fopen("file.bin", "w"); then I write random data to the file. Then I close the file with fclose(outfile); and in the next line I call my function like this showEntriesOfBlock("file.bin");
Can anybody help? I think that I might have messed up my pointers of did something wrong with the file handlers.
This is how I give data to my blocks and records.
for (int b=0; b<nblocks; ++b) { // for each block
block.blockid = b;
for (int r=0; r<MAX_RECORDS_PER_BLOCK; ++r) { // for each record
// prepare a record
record.recid = recid++;
record.num = rand() % 1000;
strcpy(record.str,"hello"); // put the same string to all records
record.valid = true;
memcpy(&block.entries[r], &record, sizeof(record_t)); // copy record to block
}
block.nreserved = MAX_RECORDS_PER_BLOCK;
block.valid = true;
fwrite(&block, 1, sizeof(block_t), outfile); // write the block to the file
}
fclose(outfile);
And here are the definitions of my structs:
// This is the definition of a record of the input file. Contains three fields, recid, num and str
typedef struct {
unsigned int recid;
unsigned int num;
char str[STR_LENGTH];
bool valid; // if set, then this record is valid
} record_t;
// This is the definition of a block, which contains a number of fixed-sized records
typedef struct {
unsigned int blockid;
unsigned int nreserved; // how many reserved entries
record_t entries[MAX_RECORDS_PER_BLOCK]; // array of records
bool valid; // if set, then this block is valid
unsigned char misc;
unsigned int next_blockid;
unsigned int dummy;
} block_t;
Here's a working version using FILE* (which I wouldn't recommend if you're learning...)
NOTE: open your files in binary mode : fopen(filename, "wb") or fopen(filename, "rb")
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cassert>
#include <fstream>
const int STR_LENGTH = 10;
const int MAX_RECORDS_PER_BLOCK = 5;
//! For my test I assumed the following definitions.
//! (i.e. that block_t is a POD.)
// This is the definition of a record of the input file. Contains three fields, recid, num and str
typedef struct
{
unsigned int recid;
unsigned int num;
char str[STR_LENGTH];
bool valid; // if set, then this record is valid
} record_t;
// This is the definition of a block, which contains a number of fixed-sized records
typedef struct
{
unsigned int blockid;
unsigned int nreserved; // how many reserved entries
record_t entries[MAX_RECORDS_PER_BLOCK]; // array of records
bool valid; // if set, then this block is valid
unsigned char misc;
unsigned int next_blockid;
unsigned int dummy;
} block_t;
void showEntriesOfBlock(const char *filename)
{
FILE* testfile = fopen(filename, "rb");
assert(testfile);
if (!testfile)
{
perror("Error");
return;
}
block_t block;
while(fread(reinterpret_cast<char*>(&block), sizeof(block_t), 1, testfile))
{
if (ferror(testfile))
{
perror("Error while reading");
return;
}
//print block contents
for (int i = 0; i < block.nreserved; ++i)
{
printf("this is block id: %d, record id: %d, num: %d, str: %s\n",
block.blockid, block.entries[i].recid, block.entries[i].num,
block.entries[i].str);
}
}
fclose(testfile);
};
int main(int argc, const char *argv[])
{
std::string filename = "g:/test.dat";
FILE* outfile;
outfile = fopen(filename.c_str(), "wb");
int nblocks = 10;
int recid = 0;
for (int b = 0; b < nblocks; ++b)
{
block_t block;
block.blockid = b;
for (int r = 0; r < MAX_RECORDS_PER_BLOCK; ++r)
{
// for each record
// prepare a record
record_t record;
record.recid = recid++;
record.num = rand() % 1000;
strcpy(record.str, "hello"); // put the same string to all records
record.valid = true;
memcpy(&block.entries[r], &record, sizeof(record_t)); // copy record to block
}
block.nreserved = MAX_RECORDS_PER_BLOCK;
block.valid = true;
fwrite(&block, sizeof(block_t), 1, outfile); // write the block to the file
}
fclose(outfile);
showEntriesOfBlock(filename.c_str());
return 0;
}
Try this:
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cassert>
#include <fstream>
#include <type_traits>
void showEntriesOfBlock(char *filename)
{
std::ifstream testfile(filename, std::ios_base::binary);
assert(testfile);
if (!testfile)
{
std::cout << "Error";
return;
}
block_t block;
int nreserved;
while (testfile)
{
//! This assumes block is a POD.
static_assert(std::is_pod<block_t>::value, "block_t is not a POD.");
testfile.read(reinterpret_cast<char*>(&block), sizeof(block_t));
nreserved = block.nreserved;
//print block contents
for (int i = 0; i < nreserved; ++i)
{
printf("this is block id: %d, record id: %d, num: %d, str: %s\n",
block.blockid, block.entries[i].recid, block.entries[i].num,
block.entries[i].str);
}
}
testfile.close();
};