Why is this cppreference demo program causing a segmentation fault? - c++

I'm reviewing a variant of the std::move function by testing it on my compiler. For some reason this program fails in both latest clang++ and g++4.8. In my opinion this looks like a correct program that should work.
g++-4.8 -std=c++1y -O3 -Wall -pthread main.cpp && ./a.out
terminate called without an active exception
/tmp/1370796977-600590525/cmd.sh: line 7: 22819 Aborted (core dumped) ./a.out
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <thread>
#include <chrono>
void f(int n)
{
std::this_thread::sleep_for(std::chrono::seconds(n));
std::cout << "thread " << n << " ended" << '\n';
}
int main()
{
std::vector<std::thread> v;
v.emplace_back(f, 1);
v.emplace_back(f, 2);
v.emplace_back(f, 3);
std::list<std::thread> l;
for(auto& t : l) t.join();
}
I notice that the part that causes the error is the emplace_back lines. When I remove them the program compiles normally. Why is this happening and why is it failing on all compilers I've tried thus far?

You are not joining the threads in main(). You need
for(auto& t : v) t.join();
// ^ Look, v not l
Alternatively, place this line before your original loop to move the threads from the v into l:
std::move(v.begin(), v.end(), std::back_inserter(l));
for(auto& t : l) t.join();

you try iterate over empty l, but 'join is not accomplished for real threads

You seem to leave the list empty, and exit main with unjoined threads in v.
IIRC destructor of std::thread calls terminate if not joined.

Related

Is Undefined Behavior To Using Invalid Iterator?

Consider this code:
#include <iostream>
#include <string>
#include <map>
int main()
{
std::map<std::string, std::string> map = {
{ "ghasem", "another" }
};
std::cout << map.find("another")->second << std::endl;
std::cout << map.size() << std::endl;
}
It will be compiled and run successfully(the process return value is 0), but we couldn't see the output of map.size(). Neither -fsanitize=address nor -fsanitize=undfined reports any problem. I compiled with GCC-11.2.1 and Clang-13.0.0, both are the same. And running the code step by step using GDB-11.1-5 will not help and all the steps will be run successfully.
But if I reorder the last two lines:
#include <iostream>
#include <string>
#include <map>
int main()
{
std::map<std::string, std::string> map = {
{ "ghasem", "another" }
};
std::cout << map.size() << std::endl;
std::cout << map.find("another")->second << std::endl;
}
I will get a Segmentation Fault and now ASAN could report the error.
And my question here is: Is the code cause some sort of Undefined Behavior? How could I detect those errors?
Environment:
OS: Fedora 35
Compiler(s):
GCC 11.2.1
Clang 13.0.0
Additional Compiler Flags:
Debugger: GDB 11.1-5
There is no key comparing equal to "another" in the map. Therefore map.find("another") will return the .end() iterator of the map. Dereferencing this iterator in ->second is then undefined behavior since end iterators may not be dereferenced.
Your code should check that the iterator returned from find is not the end iterator, i.e. that an element has been found.
In terms of debugging, if you are using libstdc++ as standard library implementation (which is the case with GCC and potentially with Clang), you can use -D_GLIBCXX_DEBUGon the compiler invocation to enable debug assertions in the standard library implementation which will detect this issue.

Is it possible to execute "cout" by order?

Is it possible to get the raw output as shown but with specific order(from bottom to top)?
cout<<R"(programming )";sleep(10); cout<<R"(
newbie at )";sleep(5); cout<<R"(
i'm )"; sleep(1);
output: programming------>printed third at the first line
newbie at------->printed second at the second line
i'm--------->printed first at the third line
Note: I don't mean reversing the output.
edit: as I guess the simple trick is to set their colour to black which will make them "disappear" and then by using nested for loop I can move through lines and change the colour of their one by one to white again with delay but i dont have an idea about how to do it practically
#include <chrono>
#include <future>
#include <iostream>
#include <thread>
int main()
{
using namespace std::chrono_literals;
auto print_first_line = std::async(std::launch::async, []() {
std::this_thread::sleep_for(6s);
std::cout << "programming\n" << std::flush;
});
auto print_second_line = std::async(std::launch::async, []() {
std::this_thread::sleep_for(3s);
std::cout << "newbie at\n" << std::flush;
});
auto print_third_line = std::async(std::launch::async, []() {
std::this_thread::sleep_for(1s);
std::cout << "i'm\n" << std::flush;
});
print_first_line.wait();
print_second_line.wait();
print_third_line.wait();
return 0;
}
As stated in the comments, it is not possible to control std::cout in this way. But it is possible to use threads to control the timing for you. This is a quick & dirty example of using std::async from <future> to multi-thread your print statements.
The first argument to std::async explicitly tells it to launch asynchronously as it can launch without creating a new thread. The second argument is a lambda with the sleep timer and the print statement.
It is worth noting that you will likely need an additional compiler argument. My current testing is in the WSL (Debian), so the compile command I'm using is clang++ -Wall -Wextra -pthread main.cpp where -pthread is the argument enabling multi-threading. For your platform it may be different.
As suggested, this scenario might be better served with a more generic function; something like delay_print(). Here's a possible implementation.
#include <array>
#include <chrono>
#include <cstdint>
#include <future>
#include <iostream>
#include <string>
#include <thread>
void delay_print(const std::chrono::duration<std::int64_t> &time,
std::string message)
{
std::this_thread::sleep_for(time);
std::cout << message << std::flush;
}
int main()
{
using namespace std::chrono_literals;
std::array<int, 4> seconds{7, 4, 2, 1};
std::array<std::string, 4> phrases{"How\n", "Now\n", "Brown\n", "Cow\n"};
auto print_line_01 =
std::async(std::launch::async, &delay_print,
std::chrono::seconds(seconds[0]), phrases[0]);
auto print_line_02 =
std::async(std::launch::async, &delay_print,
std::chrono::seconds(seconds[1]), phrases[1]);
auto print_line_03 =
std::async(std::launch::async, &delay_print,
std::chrono::seconds(seconds[2]), phrases[2]);
auto print_line_04 =
std::async(std::launch::async, &delay_print,
std::chrono::seconds(seconds[3]), phrases[3]);
print_line_01.wait();
print_line_02.wait();
print_line_03.wait();
print_line_04.wait();
return 0;
}

Is std::mutex recursive (ie non-reentrant)?

Test environment: Ubuntu 18.04.3 LTS g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0.
Can std::mutex be reentrant? Why does the following test code 1 pass?
code1:
#include <iostream>
#include <mutex>
std::mutex g_mtx4val;
int g_val = 5;
void test() {
std::lock_guard<std::mutex> lck(g_mtx4val);
std::cout << "g_val=" << g_val << std::endl;
if (g_val > 0) {
--g_val;
test();
}
}
int main() {
test();
std::cout << "done ...." << std::endl;
return 0;
}
peanut#peanut:~/demo$ g++ test.cpp
peanut#peanut:~/demo$ ./a.out
g_val=5
g_val=4
g_val=3
g_val=2
g_val=1
g_val=0
done ...
code2:
// Same code 1
int main() {
std::thread t1(test);
t1.join();
std::cout << "done ...." << std::endl;
return 0;
}
peanut#peanut:~/demo$ g++ test2.cpp -lpthread
peanut#peanut:~/demo$ ./a.out
g_val=5
^C
peanut#peanut:~/demo$
code2 has a deadlock.
Why code1 can pass the test?
From the documentation page:
mutex offers exclusive, non-recursive ownership semantics
So the answer to the question in the title is no.
Can std::mutex be reentrant?
No, but if you want a recursive mutex, the std::recursive_mutex class provides that functionality.
Why does the following test code 1 pass?
What behavior were you expecting to see? The std::mutex documentation page simply says:
A calling thread must not own the mutex prior to calling lock or try_lock.
... it doesn't say what will happen if the calling thread breaks the above rule; which means that a program that breaks the rule may "appear to work", but even so is still incorrect and buggy.

Threads in a vector can't be joined

I want to store a collection of threads in a vector, and join them all before exiting my program. I receive the following error when trying to join the first thread no matter how many I place in the collection:
system_error: thread::join failed: No such process
Here is some simple code that demonstrates my issue:
#include <thread>
#include <iostream>
#include <vector>
#include <functional>
using std::cout;
using std::endl;
using std::vector;
using std::thread;
using std::mem_fn;
int main()
{
vector<thread> threads(1);
threads.push_back(thread([]{ cout << "Hello" << endl; }));
for_each(threads.begin(), threads.end(), mem_fn(&thread::join));
// also tried --> for(thread &t : threads) t.join()
}
And I'm building it using the following (tried clang++ 4.2.1 and g++ 5.3.1):
g++ -o src/thread_test.o -c -std=c++14 src/thread_test.cpp -pthread
g++ -o thread_test src/thread_test.o -pthread
I see lots of examples doing just this around the internet. Did something change in the contract of <thread> or <vector> that's rendered these examples defunct?
NOTE: As an aside for future readers, I ended up adding the (1) constructor argument after trying {} assignment, which fails due to a private copy constructor. In trying to avoid the copy constructor I ended up allocating uninitialized threads -- careless mistake.
vector<thread> threads(1);
This creates a thread which can be accessed at index 0.
threads.push_back(thread([]{ cout << "Hello" << endl; }));
This adds a second thread which can be accessed at index 1.
for_each(threads.begin(), threads.end(), mem_fn(&thread::join));
This is going to call join on both thread objects. However, the first one was never started therefore it is not joinable.
Instead, you could replace vector<thread> threads(1); with vector<thread> threads; threads.reserve(1); and keep using push_back.

Error compiling with <list> C++

I don't know why it doesn't compile of I erase the comment in line
/*******************************/
waitThread.push_front(workerID);
/******************************/
Only if I leave the comment, it compiles...otherwise, I get a long exception ending with "declared here"...
/usr/include/c++/4.6/thread:126:5: error: declared here
maybe there is some problem with the definition of ...
Can you explain me?
/* g++ -std=c++0x -o manyThreads manyThreads.cpp -pthread */
#include <thread>
#include <iostream>
#include <mutex>
#include <time.h>
#include <list>
std::list<std::thread::id> myList;
std::mutex mutex;
std::list<std::thread> waitThread;
void insertList(std::thread::id identifier) {
mutex.lock();
myList.push_front(identifier);
mutex.unlock();
}
int main() {
std::list<std::thread::id>::iterator id;
std::list<std::thread>::iterator threadsIter;
int counter;
for(counter=0; counter<6; counter++) {
std::thread workerID(insertList, workerID.get_id());
/*******************************/
waitThread.push_front(workerID);
/******************************/
}
for(threadsIter=waitThread.begin(); threadsIter !=waitThread.end();threadsIter++) {
threadsIter->join();
}
for(id=myList.begin(); id != myList.end(); id++) {
std::cout << *id << "\n";
}
return 0;
}
std::thread is not copyable so you can't call push_front with it. It makes no sense to copy a thread, what would it do?
You can perhaps move the thread onto the list using
waitThread.push_front(std::move(workerID));
which will of course invalidate the thread object after that line.
However this line looks strange too :-
std::thread workerID(insertList, workerID.get_id());
I doubt it's valid to call get_id on an object that isn't constructed at that point.
std::thread is not copyable so you would have to move it in:
waitThread.push_front(std::move(workerID));
alternatively, you can move it by passing a temporary:
waitThread.push_front(std::thread(insertList, workerID.get_id());
It's not a comment, but a valid and (probably) essential statement in your program:
/*******************************/ -- comment
waitThread.push_front(workerID); -- statement
/******************************/ --comment