My code runs ok when thread number is 15 or less, but when I run it with larger thread number (but still a very tiny number) say 50. I ran into following error when main function exits, seems like error occurs in the cleaning up process. I couldn't figure out where the bug is. My development tool is Visual Studio 2017. Here's my code:
threadsafe_queue
class:
#pragma once
#include <memory>
#include <mutex>
template<typename T>
class threadsafe_queue
{
private:
struct Node {
std::shared_ptr<T> data;
std::unique_ptr<Node> next;
};
Node* tail;
std::unique_ptr<Node> head;
std::mutex head_mutex;
std::mutex tail_mutex;
std::condition_variable data_cond;
Node* get_tail();
std::unique_ptr<Node> pop_head();
std::unique_lock<std::mutex> wait_for_data();
public:
threadsafe_queue();
~threadsafe_queue();
threadsafe_queue(const threadsafe_queue& t) = delete;
threadsafe_queue operator = (const threadsafe_queue& t) = delete;
void push(T);
bool try_pop(T&);
std::shared_ptr<T> try_pop();
void wait_and_pop(T&);
std::shared_ptr<T> wait_and_pop();
bool empty();
};
using namespace std;
template<typename T>
threadsafe_queue<T>::threadsafe_queue() {
head = std::unique_ptr<Node>(new Node);
tail = head.get();
}
template<typename T>
threadsafe_queue<T>::~threadsafe_queue()
{
}
template<typename T>
typename threadsafe_queue<T>::Node* threadsafe_queue<T>::get_tail() {
lock_guard<mutex> lock(tail_mutex);
return tail;
}
template<typename T>
unique_ptr<typename threadsafe_queue<T>::Node> threadsafe_queue<T>::pop_head()
{
auto old_head = move(head);
head = move(old_head->next);
return old_head;
}
template<typename T>
unique_lock<mutex> threadsafe_queue<T>::wait_for_data()
{
unique_lock<mutex> headLock(head_mutex);
data_cond.wait(headLock, [&] {return head.get() != get_tail(); });
return std::move(headLock);
}
template<typename T>
void threadsafe_queue<T>::wait_and_pop(T & value)
{
unique_lock<mutex> lock(wait_for_data());
value = move(pop_head()->data);
}
template<typename T>
shared_ptr<T> threadsafe_queue<T>::wait_and_pop()
{
unique_lock<mutex> lock(wait_for_data());
return pop_head()->data;
}
template<typename T>
void threadsafe_queue<T>::push(T newValue)
{
shared_ptr<T> data(make_shared<T>(std::move(newValue)));
unique_ptr<Node> new_tail(new Node);
{
lock_guard<mutex> lock(tail_mutex);
tail->data = data;
Node* new_tail_ptr = new_tail.get();
tail->next = move(new_tail);
tail = new_tail_ptr;
}
data_cond.notify_one();
}
template<typename T>
bool threadsafe_queue<T>::try_pop(T & value)
{
lock_guard<mutex> headLock(head_mutex);
if (head == get_tail())
return false;
value = move(pop_head()->data);
return true;
}
template<typename T>
shared_ptr<T> threadsafe_queue<T>::try_pop()
{
lock_guard<mutex> headLock(head_mutex);
if (head == get_tail())
return shared_ptr<T>();
return pop_head()->data;
}
template<typename T>
bool threadsafe_queue<T>::empty()
{
lock_guard<mutex> lock(head_mutex);
return head.get() == get_tail();
}
main
function:
#pragma once
#include "threadsafe_queue.h"
#include <assert.h>
#include <memory>
#include <atomic>
#include <vector>
#include <thread>
using namespace std;
void worker(threadsafe_queue<int>& queue, std::atomic<int>& count, int const & pushcount, int const & popcount) {
for (unsigned i = 0; i < pushcount; i++) {
queue.push(i);
count++;
}
for (unsigned i = 0; i < popcount; i++) {
queue.wait_and_pop();
count--;
}
}
int main() {
threadsafe_queue<int> queue;
std::atomic<int> item_count = 0;
std::vector<thread*> threads;
unsigned const THREAD_COUNT=15, PUSH_COUT=100, POP_COUNT=50;
for (unsigned i = 0; i < THREAD_COUNT; i++) {
threads.push_back(new thread(worker, ref(queue), ref(item_count), ref(PUSH_COUT), ref(POP_COUNT)));
}
for (auto thread : threads) {
thread->join();
}
for (auto thread : threads) {
delete thread;
}
assert(item_count == THREAD_COUNT * (PUSH_COUT-POP_COUNT));
return 0;
}
error message:
Unhandled exception at 0x00862899 in Sample.exe: 0xC00000FD: Stack overflow
(parameters: 0x00000001, 0x00E02FDC). occurred
The location of the error is in memory
library code:
const pointer& _Myptr() const _NOEXCEPT
{ // return const reference to pointer
return (_Mypair._Get_second());
}
Aucun commentaire:
Enregistrer un commentaire