0

New to threading. I would like to have two separate threads that do two different things:

ThreadA: read a file, line by line from an input file

ThreadB: do things with the line that is previously read

How can I achieve this? Thanks in advance

    class A
    {
    //...
    public:
        void processFile(ifstream& input, string& s)
        {
            //read file line by line in ThreadA
            //process that line in ThreadB
        }
    };

    int main()
    {
        // ?
    }
Gus
  • 43
  • 7
  • 2
    First of all I recommend you take some time to read [Why is iostream::eof inside a loop condition considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – Some programmer dude Nov 26 '17 at 05:22
  • As for your problem, you *do* know about [`std::thread`](http://en.cppreference.com/w/cpp/thread/thread)? How about creating one, passing the string as an argument to the thread function, and adding the thread object to a vector (so you later can `join` all the threads)? That's the *naive* solution. If the file is large then you should do some research about *thread pools* and *work queues*. – Some programmer dude Nov 26 '17 at 05:23
  • Besides `std::thread`, also do some reading about [`std::async`](http://en.cppreference.com/w/cpp/thread/async), if you want to get back some result. – Some programmer dude Nov 26 '17 at 05:25
  • 1
    Why? There is no advantage. – user207421 Nov 26 '17 at 05:33
  • @Someprogrammerdude Not the biggest fan of eof but, the code was given by my instructor and he said to create two threads that does those things – Gus Nov 26 '17 at 05:45
  • @EJP Not sure. But it's my assignment specification. – Gus Nov 26 '17 at 05:46
  • 1
    Start learning Threading and locks. That's it – sam Nov 26 '17 at 07:12
  • *Two* threads? Then create one thread (from the `main` function) that reads lines and put the lines into a queue. Then create a second thread (also from the `main` function) that pops lines from the queue and processes them. Protect the queue with a mutex. – Some programmer dude Nov 26 '17 at 09:35
  • Your problem is poorly defined. If you only need to read a line, you don't need a loop. `main()` is also a thread, so you could read one line in `main()`, start a second thread to process it and then `join()` it afterwards. – Mark Setchell Nov 26 '17 at 10:03
  • @EJP - Sure there is an advantage, if done properly. One thread is processing the most recently read string while the other is blocked waiting for the input of the next string to complete. That's an advantage even if there's only one core. – Jive Dadson Nov 26 '17 at 11:57
  • This seems like about the worst case design possible. You'll have to convoy every line read from one thread to another, and the division of labor will not be anywhere close to even. – David Schwartz Nov 29 '17 at 04:26

2 Answers2

-1

For the assignment to make sense, one thread should be reading a new line of input while the other thread is processing the previously read line.

To answer the question as posed, one may use std::async. Include-file is <future>. See this near-duplicate.

I am tempted to post a correct program.

EDIT. I cannot help myself. This, like so many things, is simple once it's understood (and you know some tricks).

WARNING SPOILER ALERT You (OP) should not read on until after you have turned in the assignment.

int main() {
    std::ifstream input("foo.txt"); // Or whatever

    using std::string;
    using std::getline;
    using std::async;
    using std::move;

    // The function that processes the line ...
    // Notice that "line" is bound by value. Using a reference,
    // (const string &line) would create a conflict between threads.
    auto process = [](const string line)->bool {
        return !!(std::cout << line << std::endl); // or whatever...
    };

    string line;
    // The bang-bang !! turns the result of getline into bool
    bool line_ready = !!getline(input, line); // Read first line
    bool process_ok = true;
    while (line_ready && process_ok) {
        auto handle = async(std::launch::async, process, move(line)); // Launch thread
        line_ready = !!getline(input, line); // Fetch next line while processing previous
        process_ok = handle.get(); // Wait for processing to finish
    }
    return (process_ok && input.eof()) ? 0: -1;
}
Jive Dadson
  • 16,680
  • 9
  • 52
  • 65
  • I might be wording it incorrectly but yes. You are right. one thread should be reading a new line of input while the other thread is processing the previously read line. Also inside the while loop, I forgot to include if(fin.eof()) break; – Gus Nov 27 '17 at 00:40
  • fin.eof() might never be true. (Maybe someone trips over the power cord to the disk drive.) In that case, the program loop would never end. Edit the original question to reflect exactly what the assignment is, and also show your best effort. – Jive Dadson Nov 27 '17 at 01:25
  • thanks for your input. I have edited the question. Hopefully, it is a little bit clearer. Sorry I am new to this and still learning. I am just so confused about multithreading no matter how many times I've repeated reading the lectures and/or watching videos – Gus Nov 27 '17 at 04:09
-1

Threading is a difficult concept to get your mind around.

Conceptually, threads provide parallel execution paths, which appear to execute concurrently. On a multiple core processor they may actually be running simultaneously. On a single core processor, they don't actually run concurrently, but they appear to.

To use multi-threading effectively, you have to be able to break down a problem in a way where you can imagine that having two functions running simultaneously will benefit you. In your case, you desire to read information in one function, while processing the information in another completely separate function. Once you can see how to do that, you just have to run the functions on separate threads, and figure out how to get the information safely from one function to the other.

I would suggest writing a function that reads from the file, and stores the information in a queue or buffer of some sort. Write another function that takes information from the buffer or queue, and processes the information. Adhere to the rule that the read function only writes to the queue, and the processing function only reads from the queue.

Once you have those functions constructed, tackle the issue of running the functions on threads. The general concept is that you will launch a thread with the read function, and another thread with the processing function. Then you have to 'join' the threads when they get done doing what they are doing.

For the read thread, it is straight forward. Once the file has been read, and the information is all in the queue, it is done. The processing thread is a little more difficult. It needs to figure out when the information is going to quit coming. It may be necessary for the reading function to add something to the queue to indicate that the reading is done.

There are a number of ways to create the threads and run the functions on the threads. I'm pretty sure that your instructor is recommending ways of doing that.

ttemple
  • 852
  • 5
  • 20