- A thread might have opened a file for writing, and if it is killed, the file would not be closed. That is trouble.
- A thread might have acquired a lock on computer resources for its sole use. If the thread is killed, the resources will remain locked, and other threads and processes will not be able to use the resources.
- Memory allocated has to be released. The thread might have allocated some memory for some purpose. If the thread is killed, the memory will remain falsely allocated and unavailable for other threads and processes. That is a memory leak.
These reasons and any other means that, if a thread is killed, resources that it might have acquired would not be released for use by other threads and processes. When a thread completes naturally, any resource acquired is released.
The typical motive for killing a thread is that the user no longer needs the result of the thread.
There is some good news: C++20 is the latest version of C++ today. The thread class of C++20 has components to release the resources, of a thread, before its natural end and stop it before its natural end. In this way, C++ is stopping the thread and not killing the thread. Put another way, C++20 is killing the thread responsibly. The releasing of resources and stopping of the thread are automatic. Note: not all threads can be stopped this way. Such threads would complete naturally, even if an attempt is made to stop them.
The thread library has the following classes for stopping with the release of resources: stop_token, stop_source, and stop_callback. Each of these classes can have objects instantiated from. However, only stop_token and stop_source are considered in this tutorial.
The command to run a program of threads, with the g++ compiler, for C+20, should be similar to:
This tutorial explains how to stop a thread with resources released. Stopping a thread with resources released is a responsible way of killing a thread. This tutorial begins with a summary of codding a thread.
Article Content
- Thread Coding Summary
- The jthread Class
- Request to stop a Thread
- Is Stop Possible?
- Has Stop Request been made?
- Conclusion
Thread Coding Summary
A running program in C++ is a process. A thread is a sub-process of a process. A simple C++ program has just one thread, which is the main() function. The main() function is not a formally declared thread. Any other thread for the same program must be formally declared. There can be more than one thread in a program.
A thread is instantiated from a thread class of the thread library. The first argument of the declaration of a thread object is the name of a top-level function. The top-level function is the effective thread. When the object is instantiated, the top-level function starts executing (running).
There is a calling thread and a called thread. Unfortunately, if the called thread is not joined from the function body of the called thread, the calling thread may complete its execution without the called thread having completed its own execution. This means trouble. So, the function body of the calling thread should always join the called thread after the instantiation of the called thread.
In the following program, a thread object is instantiated, using the top-level function, fn():
#include <thread>
using namespace std;
void fn() {
cout <<"first code segment of thread" <<endl;
cout <<"second code segment of thread" <<endl;
}
int main()
{
thread thr(fn);
thr.join();
return 0;
}
The output is:
second code segment of thread
Note the inclusion of the thread library. Note how the first and second statements of the main function have been coded. The main() function is the main thread. fn() is a top-level function.
The jthread Class
The jthread is a class defined in the thread library. It is like the thread class but has the advantage that it can be used to stop a thread by releasing resources. It has member functions to return a stop_token object and a stop_source object. The member functions are:
stop_token get_stop_token()
It also has the member function to make a stop request, which is:
As of now, in October 2021, many C++ compilers are still implementing the jthread class. However, the code samples given below should work when your compiler has implemented the jthread class.
Request to stop a Thread
Stopping the thread means stopping the top-level function from running. A request to stop means that the thread should stop as soon as possible. If the request is not granted, the thread will run to completion and not stop before its end.
As indicated above, a thread instantiated from the jthread has the features to kill a thread responsibly (stop a thread from releasing its resources). The member function to request this stop is:
The return value is true if the request was accepted and false otherwise. Accepting the request does not guarantee that the thread will stop as soon as possible. It may not be possible to implement the request, and the thread will not stop until its natural end. That is, returning true does not mean that stopping is possible. The following program illustrates the use of this member function of the jthread object:
#include <thread>
using namespace std;
void fn() {
cout <<"first code segment of thread" <<endl;
cout <<"second code segment of thread" <<endl;
}
int main()
{
jthread thr(fn);
thr.request_stop();
thr.join();
return 0;
}
This program is similar to the above, but for two points:
- The thread, thr is instantiated from the jthread class.
- The statement (request) to stop the thread as soon as possible is placed before the join() statement. In this case, the calling thread is to stop the called thread from continuing to execute.
Is Stop Possible?
In some situations, it is not possible to stop a thread. However, the programmer cannot know if a thread can be stopped or not. In this case, the programmer has to inquire. The stop_source has the member function,
If the return value is true, then it is possible to stop the thread before its natural end. If the return value is false, it is impossible to stop the thread before its natural end. jthread has a method that can return the stop_source object.
So, it may be better to ask if a thread can be stopped before stopping the thread. The following program illustrates this:
#include <thread>
using namespace std;
void fn() {
cout <<"first code segment of thread" <<endl;
cout <<"second code segment of thread" <<endl;
}
int main()
{
jthread thr(fn);
stop_source ss = thr.get_stop_source();
if (ss.stop_possible())
thr.request_stop();
else
cout <<"Thread could be stopped!" <<end;
thr.join();
return 0;
}
The stopping code segment has been placed before the join statement.
Has Stop Request been made?
If it is possible to stop a thread, that still does not guarantee that a request_stop() statement will succeed in stopping the thread before its natural end. If the thread has not stopped before its natural end as hoped for, then the programmer may want to know if the thread had been asked to stop with the request_stop() statement.
The stop_token object has the member function,
This function returns true if a stop request has been made and false otherwise. The jthread object can return a stop_token object, with its member function,
The following main() function code illustrates how to know if a request_stop has been issued:
{
jthread thr(fn);
stop_source ss = thr.get_stop_source();
if (ss.stop_possible())
thr.request_stop();
else
cout <<"Thread could be stopped!" <<end;
stop_token st = thr.get_stop_token();
if (st.stop_requested())
cout <<"Still waiting for thrread to stop." <<endl;
else
thr.request_stop();
thr.join();
return 0;
}
All the stopping code is before the join statement. Do not confuse between request_stop() and stop_requested() functions.
Conclusion
A thread can be killed responsibly with C++20 and higher. This means stopping the thread with the resources of the thread, freed. The thread library has the stop_token, stop_source, stop_callback, and jthread classes for killing a thread responsibly. To use the stop_token, stop_source, and stop_callback instantiated objects, create the thread with the jthread class. The jthread class is in the thread library, which has to be included in the C++ program.
The jthread class has member functions to return the stop_token and stop_source objects. The jthread class itself has the member function, request_stop(), to stop a thread. This request is likely to be granted, but there is no guarantee that it will be granted. If the request is granted, then the thread stops as soon as possible, without reaching its natural end, everything being equal.
The stop_source object can be used to know if stopping a thread is possible. The stop_token object can be used to know if a request_stop() has been issued. Once a stop request has been made, it cannot be withdrawn (a subsequent stop request has no effect).