Help with threads

Hello everyone! Here is the code of the Universal Turing Machine from a few text files which can execute either 1.txt or 2.txt or 3.txt or 4.txt.
I need to figure out a way how can I make this Turing Machine parallel - to make the program to execute all four text files at once. I know that it is possible to use threads, but I am not that familiar with them and cannot understand them. Any help and hints are truly appreciated!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <thread>

using namespace std;
using namespace std::chrono;
using namespace std::this_thread;

void Universal_Turing_Machine(string current_state[], char current_symbol[], char new_symbol[], char direction[], string new_state[], string tape, int head, int number_of_rows)
{
	int n = tape.length();
	string next_state = "0";
	string cursor = " ";
	for (auto i = 0; i < n - 1; i++)
	{
		cursor.append(" ");
	}
	cout << n;
	cout << cursor << endl;
	cursor[head] = '^';
	while (next_state != "X")
	{
		for (auto i = 0; i < number_of_rows; i++)
		{
			if (next_state == current_state[i])
			{
				if (current_symbol[i] == tape[head])
				{
					tape[head] = new_symbol[i];
					next_state = new_state[i];
					if (next_state == "X")
					{
						break;
					}
					if (direction[i] == 'R')
					{
						cursor[head] = ' ';
						head++;
						cursor[head] = '^';
					}
					else
					{
						cursor[head] = ' ';
						head--;
						cursor[head] = '^';
					}
				}
			}
		}
		system("cls");
		cout << tape << endl;
		cout << cursor << endl;
		sleep_for(milliseconds(60));
	}
}

int main()
{
	string tape, current_state[100], new_state[100];
	int head, file = 0, number_of_rows = 0;
	char direction[100], current_symbol[100], new_symbol[100];
	ifstream fin;
	while (file > 4 || file < 1)
	{
		cout << "Choose a text file!" << endl;
		cout << "1) 1.txt\n2) 2.txt\n3) 3.txt\n4) 4.txt" << endl;
		cin >> file;
		switch (file)
		{
		case 1: { fin.open("1.txt"); break; }
		case 2: { fin.open("2.txt"); break; }
		case 3: { fin.open("3.txt"); break; }
		case 4: { fin.open("4.txt"); break; }
		default: { cout << "Your choice is unavailable! Pick between 1, 2, 3, 4!"; sleep_for(seconds(2)); system("cls"); break; }
		}
	}
	cout << "You chose " << file << ".txt!" << endl;
	fin >> head;
	fin >> tape;
	while (!fin.eof())
	{
		fin >> current_state[number_of_rows] >> current_symbol[number_of_rows] >> new_symbol[number_of_rows] >> direction[number_of_rows] >> new_state[number_of_rows];
		number_of_rows++;
	}
	fin.close();
	number_of_rows--;
	cout << "Data from the text file was read successfully!" << endl;
	sleep_for(seconds(2));
	system("cls");
	cout << tape << endl;
	Universal_Turing_Machine(current_state, current_symbol, new_symbol, direction, new_state, tape, head, number_of_rows);
}
threads can get very complex, but they don't have to be when you are just learning. lets keep this simple for now.

- you need a function which to thread. basically, you want the computer to do this block of work in parallel; this is either your Universal_Turing_Machine or a mashup of your main and that function (I can't study your code in depth right now).
- you need a thread library. pthreads works on everything that I know of. windows has a very similar but slightly different names version in visual studio.

- so you create a thread variable. this is (effectively) just a pointer, really, that lets you access the process if you need to kill it or the like.

- and you need to kick it off.

put all that together and you get something like this:

void foothread(type stuff)
{ do things();}

main()
thread a,b,c,d;
//you may need 1 more function call here to initialize something
a = beginthread(foothread, data1);
b = beginthread(foothread, data2);
c = beginthread(foothread, data3);
d = beginthread(foothread, data4);

while(all the threads are not yet done)
sleep(100); //you don't have to busy-wait here, you can do other work, I am keeping this simple

and so on.

so long as foo() is not doing anything that would break if the 4 things running in parallel mash each other (eg, writing to the same data, updating the same global variable, things like that) this is enough to get you started.

From here, you need to download a thread library (or use what you have eg visual's built in one) and read the documentation on how to do it, but its really going to look very much like what I have above apart from minor details.

now, your code isn't going to do well like this. Your machine has system("cls") for example, so thread 1 may be clearing the screen while thread 2 just wrote to it, and the output of those cout statements is going to get very jumbled up and unclear what statement belonged to which thread. Before you go too far, you need to deal with this issue. For a simple program you can store what you would have written in each thread into a string and write those one at a time in sequence instead of parallel. More complex programs have to find other ways to deal with this sort of problem (this is where threading starts to get complicated and aggravating). You may be on a system that allows you to talk to multiple console windows at once; that is another option for handling the problem. There may be other things that you will need to rewrite before you can do this cleanly, but the actual threading mechanics are not so bad.

> I need to figure out a way how can I make this Turing Machine parallel -
> to make the program to execute all four text files at once.

The simplest way to execute code asynchronously is to use std::async
Write a wrapper function which receives the name of a file, opens it, reads the data and calls the Turing Machine function. Execute this function asynchronously, in parallel, one for each input file.

Something along these lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>
#include <random>
#include <future>
#include <vector>
#include <iomanip>

void Universal_Turing_Machine( std::string current_state[], char current_symbol[],
                               char new_symbol[], char direction[], std::string new_state[],
                               std::string tape, int head, int number_of_rows )
{
    // the code for the function

}

void process_file( const std::string& file_name )
{
    static std::mutex cout_mutex ; // static: shared across all threads

    {
        std::lock_guard<std::mutex> lock(cout_mutex) ;
        std::cout << "function process_file, file name: " << std::quoted(file_name)
                  << ", executed by thread " << std::this_thread::get_id() << '\n' ;
    }

    if( std::ifstream fin{file_name} )
    {
        std::string tape ;
        int head ;
        if( fin >> tape >> head )
        {
            const int MAX_ROWS = 100 ;
            std::string current_state[MAX_ROWS], new_state[MAX_ROWS];
            char direction[MAX_ROWS], current_symbol[MAX_ROWS], new_symbol[MAX_ROWS];

            int number_of_rows = 0 ;
            while( number_of_rows < MAX_ROWS &&
                   fin >> current_state[number_of_rows] >> current_symbol[number_of_rows]
                       >> new_symbol[number_of_rows] >> direction[number_of_rows]
                       >> new_state[number_of_rows] ) ++number_of_rows ;

            Universal_Turing_Machine( current_state, current_symbol, new_symbol, direction,
                                      new_state, tape, head, number_of_rows );
        }
    }

    // debug stub: mimic a time consuming operation by sleeping for a while
    std::this_thread::sleep_for( std::chrono::milliseconds( 100 + std::random_device{}() % 512 ) ) ;

    {
        std::lock_guard<std::mutex> lock(cout_mutex) ;
        std::cout << "thread " << std::this_thread::get_id()
                  << " has finished processing file " << std::quoted(file_name) << '\n' ;
    }
}

int main()
{
    // https://en.cppreference.com/w/cpp/thread/future
    std::vector< std::future<void> > futures ;

    // execute process_file asynchronously (in parallel) for each file
    // https://en.cppreference.com/w/cpp/thread/async
    for( std::string file_name : { "1.txt", "2.txt", "3.txt", "4.txt" } )
        futures.push_back( std::async( std::launch::async, process_file, file_name ) ) ;

    // wait for asynchronous execution to finish before ending the program
    // https://en.cppreference.com/w/cpp/thread/future/wait
    for( const auto& f : futures) f.wait() ;
}

http://coliru.stacked-crooked.com/a/885fe2121038ba2f
Last edited on
Topic archived. No new replies allowed.