C++互斥锁锁定错误
C++ mutex locking error
我正在使用一个具有工作窃取功能的线程池,但每当程序试图锁定工作队列中的互斥对象时,我都会收到一个异常错误。
我在Windows Visual Studio 2015和Ubuntu 14.04上都尝试过该程序,但都产生了运行时异常。
我已经对工作队列本身进行了广泛的测试,无法重现错误。如果我注释掉try_steal函数,我不会遇到任何错误。最后,我用std::recursive_mutex替换了std::mutex,但仍然会得到同样的错误。
我认为异常发生在线程池的解构过程中,即一个线程试图读取另一个已经被破坏的线程的工作队列。但是,即使在程序结束前引入了无限循环之后,也会出现同样的异常。
我想知道是否还有其他我不想检查的东西,下面你会发现相关的代码以及VS2015和Linux调用堆栈。
谢谢你的帮助。
Windows调用堆栈:
msvcp140d.dll!mtx_do_lock(_mtx_internalimp_t*mtx,const xtime*target)msvcp140d.dll_Mtx_lock(_Mtx_internal_inmp_t*Mtx)thread_pool_test.exe!std::_Mtx_lockX(_Mtx_internal_inmp_t*_Mtx)thread_pool_test.exe!std::_Mutex_base::lock()thread_pool_test.exe!std::lock_guard::lock_guard(std::mutex&_Mtx)thread_pool_test.exe!work_stealing_queue::try_steal(function_wrapper&res)thread_pool_test.exe!thread_pool_steal::pop_task_from_other_thread_queue(function_wrapper&task)thread_pool_test.exe!thread_pool_steal::run_pending_task()thread_pool_test.exe!thread_pool_steal::worker_thread(未签名的int my_index_)thread_pool_test.exe!std::_Invoker_pmf_pointer::_Call(void(unsigned int)*_pmf,thread_pool_steal*&_Arg1,int&<_Args2_0>)第1373 C行++thread_pool_test.exe!std::invoke(void(unsigned int)*&_对象,thread_pool_steal*&<_Args_0>,int&<_Args_1>)thread_pool_test.exe!std::_LaunchPad,std::default_delete>>::_Execute<0,1,2>(std::元组&_Tup,std::整数序列__formal)thread_pool_test.exe!std::_LaunchPad,std::default_delete>>::Run(std::.LaunchPad、std::default _delete>>*_Ln)thread_pool_test.exe!std::_LaunchPad,std::default_delete>>::_Go()thread_pool_test.exe!std::_Pad::_Call_func(无效*_Data)ucrtbased.dll!0fa27e48()[下面的帧可能不正确和/或丢失,没有为基于ucrt.dll加载符号]ucrtbased.dll!0fa27b8()kernel32.dll@BaseThreadInitThunk@12()ntdll.dll!___RtlUserThreadStart@8()ntdll.dll!__RtlUserThreadStart@8()
Linux调用堆栈:
[New Thread 0x7ffff6f5d700 (LWP 4395)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff6f5d700 (LWP 4395)]
__GI___pthread_mutex_lock (mutex=0x0)
at ../nptl/pthread_mutex_lock.c:66
66 ../nptl/pthread_mutex_lock.c: No such file or directory.
(gdb) bt
#0 __GI___pthread_mutex_lock (mutex=0x0)
at ../nptl/pthread_mutex_lock.c:66
#1 0x0000000000401f53 in __gthread_mutex_lock (__mutex=0x50)
at /usr/include/x86_64-linux-gnu/c++/4.9/bits/gthr-default.h:748
#2 0x00000000004023ba in std::mutex::lock (this=0x50)
at /usr/include/c++/4.9/mutex:135
#3 0x000000000040370a in std::lock_guard<std::mutex>::lock_guard (
this=0x7ffff6f5cd10, __m=...) at /usr/include/c++/4.9/mutex:377
#4 0x00000000004030fa in work_stealing_queue::try_steal (this=0x0,
res=...) at Source.cpp:250
#5 0x00000000004032c8 in thread_pool_steal::pop_task_from_other_thread_queue (this=0x7fffffffdac0, task=...) at Source.cpp:302
#6 0x00000000004035e4 in thread_pool_steal::run_pending_task (
this=0x7fffffffdac0) at Source.cpp:358
#7 0x00000000004031ba in thread_pool_steal::worker_thread (
this=0x7fffffffdac0, my_index_=0) at Source.cpp:283
#8 0x000000000040d3d4 in std::_Mem_fn<void (thread_pool_steal::*)(unsigned int)>::operator()<int, void>(thread_pool_steal*, int&&) const (
this=0x62af78, __object=0x7fffffffdac0)
at /usr/include/c++/4.9/functional:569
#9 0x000000000040cec9 in std::_Bind_simple<std::_Mem_fn<void (thread_pool_steal::*)(unsigned int)> (thread_pool_steal*, int)>::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) (this=0x62af68)
at /usr/include/c++/4.9/functional:1700
#10 0x000000000040c87f in std::_Bind_simple<std::_Mem_fn<void (thread_pool_steal::*)(unsigned int)> (thread_pool_steal*, int)>::operator()() (
this=0x62af68) at /usr/include/c++/4.9/functional:1688
#11 0x000000000040c4ea in std::thread::_Impl<std::_Bind_simple<std::_Mem_fn<void (thread_pool_steal::*)(unsigned int)> (thread_pool_steal*, int)> >::_M_run() (this=0x62af50) at /usr/include/c++/4.9/thread:115
#12 0x00007ffff78f7e40 in ?? ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#13 0x00007ffff7bc4182 in start_thread (arg=0x7ffff6f5d700)
at pthread_create.c:312
#14 0x00007ffff735e47d in clone ()
at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
代码:
class work_stealing_queue
{
private:
typedef function_wrapper data_type;
std::deque<data_type> the_queue;
mutable std::mutex the_mutex;
bool empty() const
{
std::lock_guard<std::mutex> lock(the_mutex);
return the_queue.empty();
}
bool try_steal(data_type& res)
{
std::lock_guard<std::mutex> lock(the_mutex);
if (the_queue.empty())
{
return false;
}
res = std::move(the_queue.back());
the_queue.pop_back();
return true;
}
};
class thread_pool_steal
{
typedef function_wrapper task_type;
std::atomic_bool done;
threadsafe_queue<task_type> pool_work_queue;
std::vector<std::unique_ptr<work_stealing_queue> > queues;
std::vector<std::thread> threads;
static thread_local work_stealing_queue* local_work_queue;
static thread_local unsigned int my_index;
join_threads joiner;
bool pop_task_from_other_thread_queue(task_type& task)
{
for (unsigned i = 0; i<queues.size(); ++i)
{
unsigned const index = (my_index + i + 1) % queues.size();
if (queues[index]->try_steal(task))
{
return true;
}
}
return false;
}
public:
thread_pool_steal() : done(false), joiner(threads)
{
unsigned const thread_count = std::thread::hardware_concurrency();
try
{
for (auto i = 0; i<thread_count; ++i)
{
queues.push_back(std::unique_ptr<work_stealing_queue>(std::make_unique<work_stealing_queue>()));
threads.push_back(std::move(std::thread(&thread_pool_steal::worker_thread, this, i)));
}
}
catch (...)
{
done = true;
throw;
}
};
~thread_pool_steal()
{
done = true;
};
在Linux中,在调用pthread_mutex_lock()之前,必须初始化"the_mutex"。参见Unix网络编程第1卷第2版(W.Richard Stevens)第626页。它说:"如果互斥变量是静态分配的,我们必须将其初始化为常量PTHREAD_mutex_INITIALIZER。"
pthread_mutex_t the_mutex = PTHREAD_MUTEX_INITIALIZER;
出现此错误的原因似乎是std::vector不是线程安全的。当主线程添加到work_stealing_queue的向量queues时,新生成的线程调用queues.size()。我猜size()函数在队列中最新的work_steaing_queue准备就绪之前递增。解决方案是创建两个单独的循环,一个用于创建队列中的所有work_stealing_queue,另一个用于使用函数worker_thread运行线程。
for(auto i=0;i<thread_count;++i)
{
queues.push_back(std::unique_ptr<work_stealing_queue> (std::make_unique<work_stealing_queue>()));
}
for(auto i=0;i<thread_count;++i) // Seperate becuse std::vector is not thread safe and causes issues when size() is used
{
threads.push_back(std::thread(&thread_pool_steal::worker_thread,this,i));
}
- 警告处理为错误这里有什么问题
- "error: no matching function for call to"构造函数错误
- boost::进程间消息队列引发错误
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- QT在错误的班级中寻找空位
- vector.resize()中的分配错误
- 代码在main()中运行,但在函数中出现错误
- 释放错误后堆使用
- (C++)分析树以计算返回错误值的简单算术表达式
- Project Euler问题4的错误解决方案
- 错误:"shared_mutex"不是使用读取器锁定 = std::shared_lock<std::shared_mutex> 的"std"的成员;
- boost线程锁定错误
- 升压错误锁定问题
- RocksDB IO错误:锁定db/lock:没有可用的锁
- 锁定'vector'文件中的错误
- 这个解决方案对MSVC的双重检查锁定错误和函数静态有什么问题?
- 托管c++ dll加载器锁定错误,静态链接到本地c++库
- C++互斥锁锁定错误
- 为什么pthread_mutex_t尝试锁定来自两个不同进程的共享内存时会出现段错误