when pthread_once encounters reentrancy - multithreading

What would happen in the situation below?
#include <pthread.h>
#include <stdio.h>
static pthread_once_t random_is_initialized = PTHREAD_ONCE_INIT;
void initialize(){
foo("init()");
}
int foo(char *str)
{
pthread_once(&random_is_initialized, initialize);
printf("%s", str);
}
int main(){
foo("main");
}
Will it cause infinite recursion? Thanks!
[edit] I ran the code. It seems the code does not cause infinite recursion, but it blocks at the second pthread_once that I have to "ctrl + c". That is, deadlock happened.
(gdb) bt
#0 0x0012d422 in __kernel_vsyscall ()
#1 0x00139404 in pthread_once () from /lib/tls/i686/cmov/libpthread.so.0
#2 0x080484a3 in foo (str=0x8048590 "init()") at main.c:12
#3 0x08048486 in initialize () at main.c:6
#4 0x00139430 in pthread_once () from /lib/tls/i686/cmov/libpthread.so.0
#5 0x080484a3 in foo (str=0x804859a "main") at main.c:12
#6 0x080484ce in main () at main.c:17

On a proper pthread implementation init_routine() will only be called once so there will be no infinite recursion. However, all other callers to pthread_once() must wait until init_routine() has finished executing. In this case it will never finish so you've created a deadlock.

Related

C++11 shared pointer thread safety is broken?

As per C++ documentation, control block of the shared_ptr is thread-safe. ie, operator= or reset are accessible to multiple threads without explicit locking.
But I see a strange behavior; shared object is double freed occasionally:
#include <iostream>
#include <memory>
#include <unistd.h>
using namespace std;
class MyClass {
public:
MyClass(string x) : name(x) {cout<<"C->"<<name<<endl;};
~MyClass() {cerr<<"D->"<<name<<endl;};
string name;
};
shared_ptr<MyClass> a;
void* tfunc(void*) {
while(1){
{
shared_ptr<MyClass> s = a;
usleep(5);
}
}
}
int main(void) {
pthread_t threadid;
a = make_shared<MyClass>("a");
if(pthread_create(&threadid, NULL, tfunc, NULL)) {
cout<<"pthread_create error"<<endl;
return -1;
}
while(1){
usleep(5);
a = make_shared<MyClass>("b");
}
pthread_join(threadid, NULL);
return 0;
}
Here is the Address Sanitizer output:
==28588==ERROR: AddressSanitizer: heap-use-after-free on address 0xb33a7ad4 at pc 0x080490c4 bp 0xb54ff1d8 sp 0xb54ff1c8
WRITE of size 4 at 0xb33a7ad4 thread T1
#0 0x80490c3 in __exchange_and_add /usr/include/c++/6/ext/atomicity.h:49
#1 0x80491ed in __exchange_and_add_dispatch /usr/include/c++/6/ext/atomicity.h:82
#2 0x8049a9e in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/6/bits/shared_ptr_base.h:147
#3 0x80498a3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/6/bits/shared_ptr_base.h:662
#4 0x804977e in std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/6/bits/shared_ptr_base.h:928
#5 0x8049797 in std::shared_ptr<MyClass>::~shared_ptr() /usr/include/c++/6/bits/shared_ptr.h:93
#6 0x80492d7 in tfunc(void*) /tmp/main.cpp:19
#7 0xb7248c4e (/usr/lib/i386-linux-gnu/libasan.so.3+0x26c4e)
#8 0xb6ea5304 in start_thread (/lib/i386-linux-gnu/libpthread.so.0+0x6304)
#9 0xb6fb347d in __clone (/lib/i386-linux-gnu/libc.so.6+0xe947d)
0xb33a7ad4 is located 4 bytes inside of 36-byte region [0xb33a7ad0,0xb33a7af4)
freed by thread T0 here:
#0 0xb72e7174 in operator delete(void*) (/usr/lib/i386-linux-gnu/libasan.so.3+0xc5174)
#1 0x804ace0 in __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2> >::deallocate(std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2>*, unsigned int) /usr/include/c++/6/ext/new_allocator.h:110
#2 0x804ab07 in std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2> > >::deallocate(std::allocator<std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2> >&, std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2>*, unsigned int) /usr/include/c++/6/bits/alloc_traits.h:442
#3 0x804a818 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2> > >::~__allocated_ptr() /usr/include/c++/6/bits/allocated_ptr.h:73
#4 0x804b0aa in std::_Sp_counted_ptr_inplace<MyClass, std::allocator<MyClass>, (__gnu_cxx::_Lock_policy)2>::_M_destroy() /usr/include/c++/6/bits/shared_ptr_base.h:537
#5 0x8049bbe in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/6/bits/shared_ptr_base.h:166
#6 0x80498a3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/6/bits/shared_ptr_base.h:662
#7 0x804977e in std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/6/bits/shared_ptr_base.h:928
#8 0x8049cd4 in std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>::operator=(std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>&&) /usr/include/c++/6/bits/shared_ptr_base.h:1003
#9 0x8049a7c in std::shared_ptr<MyClass>::operator=(std::shared_ptr<MyClass>&&) /usr/include/c++/6/bits/shared_ptr.h:294
#10 0x8049430 in main /tmp/main.cpp:35
#11 0xb6ee2275 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18275)
GCC-6.2 and LLVM-3.9 show same behavior. Is it a bug in the C++ library?
No. = and reset are not thread safe. The shared_ptr overloads of std::atomic_... functions are needed.
"Control block is thread-safe" means you can use = and reset in multiple threads (but each thread uses a separate shared_ptr), even if all shared_ptr objects are copies of each other.

Posix Threads with Mutex

I have started working on POSIX threads. I wrote a simple code.
My question is on Mutex.
Initializing the mutex inside threaded function gives wrong result. While initializing the mutex inside main function (before creation of threads) gives proper result. Why is that happening?
The count value is expected to be 200000 but it is showing some improper value < 200000.
Here is my code.
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <malloc.h>
void *thread_handler (void *name);
unsigned long int count=0;
pthread_mutex_t lock;
void main () {
pthread_t thread_num[2];
pthread_attr_t attr;
pthread_attr_init (&attr);
int i;
for (i=0;i<2;i++) {
if (pthread_create (&thread_num[i],&attr,(void *) thread_handler,NULL)<0) {
printf ("\n Error in Creating the Threads");
}
}
for (i=0;i<2;i++) {
pthread_join(thread_num[i],NULL); //Waiting for the Thread to Exit
}
printf ("\n The value of count=%ld\n",count);
}
void *thread_handler (void *arg) {
int i;
if (pthread_mutex_init (&lock,NULL)!=0) {
printf ("\n Error in Initializing the Mutex");
}
pthread_mutex_lock (&lock);
for (i=0;i<100000;i++) {
count++;
}
pthread_mutex_unlock(&lock);
pthread_exit(NULL);
}
Thanks in Advance,
NDPrasad.
When you initialize the mutex inside the thread_handler function, it is initialized twice(because you create two threads that execute this function). It causes undefined behavior(which means that anything can happen).
A quote from here:
Attempting to initialize an already initialized mutex results in undefined behavior.

Segmentation fault in pthread_create

I'm using pthread_create to use a function from shared library. I receive Segmenation fault after the following code executes:
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
void (*GetVersion)(char *version);
void* draw(void *arg)
{
void *handle;
char *error;
handle = dlopen ("libOpenKaillera.so", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
GetVersion = dlsym(handle, "GetVersion");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
char version[4];
kailleraGetVersion(version);
puts(version);
dlclose(handle);
return NULL;
}
int main(void)
{
pthread_t tid;
pthread_create(&tid, NULL, &draw, NULL);
sleep(5000);
return 0;
}
The backtrace command says the following:
#0 0xb68e7be0 in ?? ()
#1 0xb7fa9d56 in __nptl_deallocate_tsd () at pthread_create.c:158
#2 0xb7fa9f83 in start_thread (arg=0xb7df0b40) at pthread_create.c:325
#3 0xb7ede4ce in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:129
I don't understand what a reason can cause this. Can you help me please?
after each calling of pthread_create, please remember to call pthread_join or pthread_detach to tell the thread how to perform termination. normally, please call pthread_join before exiting the creating thread (in this case, it is function main).

Incrementing a global variable with a thread

I just wrote the following code to understand better how Threads work:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
int globalVariable = 1;
void *myfunc (void *myvar);
int main (void) {
pthread_t thread1;
int waitms;
while(globalVariable <= 50){
printf("Main function: %d \n", globalVariable);
if (globalVariable==9) {
pthread_create(&thread1, NULL, myfunc, NULL);
pthread_join(thread1, NULL);
}
usleep(300000);
globalVariable++;
}
return 0;
}
void *myfunc (void *myvar){
int waitms;
while(globalVariable<=50) {
printf("Thread1: %d \n", globalVariable);
usleep(300000);
globalVariable++;
}
return 0;
}
The code must print a value of a global variable that is incremented in the main function. When this variable has the value 9, the main function calls a thread, that does the same as the original main function, but without calling another thread.
In the Output I get the first 9 prints of the main function and all the following ones are from the thread. Shouldn't they be mixed? What have I done wrong?
No because you are joining the thread1, so the main thread blocks until thread1 dies. Once thread1 dies it resumes but thread1 has incremented the globalVariable to a point where the main thread exits the first while loop.
Removing the join you will see mixed results, better still would be to move the join outside of the while loop so if thread1 is still alive when the main thread exits the loop it waits... it's most likely going to dead by that time but you should make sure your child threads have finished up before exiting the main thread.

Assertion on mutex when using multiple threads and mutexes

As a part of a project I'm writing a logger function. This logger function sends an e-mail when the program wants to log something. Since it has happened that the SMTP server was non responsive, I've decided to do the sending of the mails in a separate thread.
This thread reads messages from an std::deque which is filled by the logging function.
The thread is setup as follows:
while (!boost::this_thread::interruption_requested())
{
EmailItem emailItem;
{
boost::unique_lock<boost::mutex> lock(mMutex);
while (mEmailBuffer.empty())
mCond.wait(lock);
bufferOverflow = mBufferOverflow;
mBufferOverflow = false;
nrOfItems = mEmailBuffer.size();
if (nrOfItems > 0)
{
emailItem = mEmailBuffer.front();
mEmailBuffer.pop_front();
}
}
if (nrOfItems > 0)
{
bool sent = false;
while(!sent)
{
try
{
..... Do something with the message .....
{
boost::this_thread::disable_interruption di;
boost::lock_guard<boost::mutex> lock(mLoggerMutex);
mLogFile << emailItem.mMessage << std::endl;
}
sent = true;
}
catch (const std::exception &e)
{
// Unable to send mail, an exception occurred. Retry sending it after some time
sent = false;
boost::this_thread::sleep(boost::posix_time::seconds(LOG_WAITBEFORE_RETRY));
}
}
}
}
The function log() adds a new message to the deque (mEmailBuffer) as follows:
{
boost::lock_guard<boost::mutex> lock(mMutex);
mEmailBuffer.push_back(e);
mCond.notify_one();
}
When the main program exits, the destructor of the logger object is called. This is where it goes wrong, the application crashes with an error:
/usr/include/boost/thread/pthread/mutex.hpp:45: boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed.
The destructor merely calls an interrupt on the thread and then joins it:
mQueueThread.interrupt();
mQueueThread.join();
In the main program, I use multiple different classes which make use of boost threading and mutex as well, could this cause this behaviour? Not calling the destructor of the logger object results in no errors, as does using the logger object and not doing anything else.
My guess is I am doing something very wrong, or there is a bug in the threading library when using multiple threads divided over several classes.
Does anyone have a idea what the reason for this error might be?
EDIT:
I did as #Andy T proposed and stripped the code as much as possible. I removed nearly everything in the function which is ran in a different thread. The thread now looks like:
void Vi::Logger::ThreadedQueue()
{
bool bufferOverflow = false;
time_t last_overflow = 0;
unsigned int nrOfItems = 0;
while (!boost::this_thread::interruption_requested())
{
EmailItem emailItem;
// Check for new log entries
{
boost::unique_lock<boost::mutex> lock(mMutex);
while (mEmailBuffer.empty())
mCond.wait(lock);
}
}
}
The problem still persists. Backtracking of the problem however showed me something different from the initial code:
#0 0x00007ffff53e9ba5 in raise (sig=<value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00007ffff53ed6b0 in abort () at abort.c:92
#2 0x00007ffff53e2a71 in __assert_fail (assertion=0x7ffff7bb6407 "!pthread_mutex_lock(&m)", file=<value optimized out>, line=50, function=0x7ffff7bb7130 "void boost::mutex::lock()") at assert.c:81
#3 0x00007ffff7b930f3 in boost::mutex::lock (this=0x7fffe2c1b0b8) at /usr/include/boost/thread/pthread/mutex.hpp:50
#4 0x00007ffff7b9596c in boost::unique_lock<boost::mutex>::lock (this=0x7fffe48b3b40) at /usr/include/boost/thread/locks.hpp:349
#5 0x00007ffff7b958db in boost::unique_lock<boost::mutex>::unique_lock (this=0x7fffe48b3b40, m_=...) at /usr/include/boost/thread/locks.hpp:227
#6 0x00007ffff6ac2bb7 in Vi::Logger::ThreadedQueue (this=0x7fffe2c1ade0) at /data/repos_ViNotion/stdcomp/Logging/trunk/src/Logger.cpp:198
#7 0x00007ffff6acf2b2 in boost::_mfi::mf0<void, Vi::Logger>::operator() (this=0x7fffe2c1d890, p=0x7fffe2c1ade0) at /usr/include/boost/bind/mem_fn_template.hpp:49
#8 0x00007ffff6acf222 in boost::_bi::list1<boost::_bi::value<Vi::Logger*> >::operator()<boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list0> (this=0x7fffe2c1d8a0, f=..., a=...) at /usr/include/boost/bind/bind.hpp:253
#9 0x00007ffff6acf1bd in boost::_bi::bind_t<void, boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list1<boost::_bi::value<Vi::Logger*> > >::operator() (this=0x7fffe2c1d890) at /usr/include/boost/bind/bind_template.hpp:20
#10 0x00007ffff6aceff2 in boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list1<boost::_bi::value<Vi::Logger*> > > >::run (this=0x7fffe2c1d760)
at /usr/include/boost/thread/detail/thread.hpp:56
#11 0x00007ffff2cc5230 in thread_proxy () from /usr/lib/libboost_thread.so.1.42.0
#12 0x00007ffff4d87971 in start_thread (arg=<value optimized out>) at pthread_create.c:304
#13 0x00007ffff549c92d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#14 0x0000000000000000 in ?? ()
Might it be possible that mMutex is not unlocked in the combination of using an unique_lock() and then interrupting the thread?
do you join your thread before exiting? as tyz suggested, your thread can still keep it locked when mutex is destroyed.
[EDIT]
you didn't provide complete example that can be compiled and run, it's hard to help w/o it.
check this simple example that should be similar to your one:
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <queue>
class Test
{
public:
Test()
{
thread = boost::thread(boost::bind(&Test::thread_func, this));
}
~Test()
{
thread.interrupt();
thread.join();
}
void run()
{
for (size_t i = 0; i != 10000; ++i) {
boost::lock_guard<boost::mutex> lock(mutex);
queue.push(i);
condition_var.notify_one();
}
}
private:
void thread_func()
{
while (!boost::this_thread::interruption_requested())
{
{
boost::unique_lock<boost::mutex> lock(mutex);
while (queue.empty())
condition_var.wait(lock);
queue.pop();
}
}
}
private:
boost::thread thread;
boost::mutex mutex;
boost::condition_variable condition_var;
std::queue<int> queue;
};
int main()
{
Test test;
test.run();
return 0;
}
compare with your case
You should unlock mutex before you delete it.

Resources