boost udp::socket closes, but not freeing socket UPDATE - c++

UPDATE: If i change async_receive_from to receive_from then there will not be any problems with rebinding. Somehow async... causes that. Previously i had one thread for every socket(with receive_from), but i had to make it work in one thread as too many threads are spawned during programm runs.
Socket is closed (i have checked), but rebinding to it causes an error. Here is an example:
#include "stdafx.h"
#include "Mmsystem.h"// for accurate timers
#pragma comment (lib,"Winmm.lib")// for accurate timers
using namespace std;
typedef shared_ptr<boost::asio::ip::udp::socket> SHP_Socket;
boost::asio::io_service io_service_;
vector<int> ports;
vector<SHP_Socket> vecSock;
vector<boost::asio::ip::udp::endpoint> vecEndpoint;
vector<boost::shared_ptr<boost::thread>> receive_threads;
bool process_all_finishing;
uint8_t Data[8000];
void receive_h(boost::system::error_code ec, size_t szPack, int i)
{
if (process_all_finishing == false)
{
cout << "\n" << i;
string f = boost::to_string(Data);
int sz = f.size();
if (sz > 12)
{
vector<int> a;
for (int i = 0; i < 100; ++i)
a.push_back(i);
a.clear();
}
}
}
void Run_io()
{
while (process_all_finishing == false)
{
io_service_.run_one();
}
cout << "\nRun_io finished";
}
void receive()
{
while (process_all_finishing == false)
{
this_thread::sleep_for(chrono::milliseconds(1));
for (unsigned i = 0; i < vecSock.size(); ++i)
{
vecSock[i]->async_receive_from(boost::asio::buffer(Data, 8000), vecEndpoint[i], boost::bind(receive_h,_1,_2,i));
}
}
cout << "\nreceive finished";
}
int main()
{
timeBeginPeriod(1);
setlocale(LC_ALL, "Russian");
try
{
ports.push_back(29005);
ports.push_back(29007);
ports.push_back(29009);
ports.push_back(29001);
vecSock.resize(3);
vecEndpoint.resize(3);
for (int i = 0; i < 3; ++i)
{
vecSock[i].reset(new boost::asio::ip::udp::socket(io_service_, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), ports[i])));
}
boost::shared_ptr<boost::thread> thread_re(new boost::thread(receive));
boost::shared_ptr<boost::thread> thread_io(new boost::thread(Run_io));
receive_threads.push_back(thread_re);
receive_threads.push_back(thread_io);
cout << "\nvecSock=3 created, giving it to work for 1 second:";
this_thread::sleep_for(chrono::seconds(1));
process_all_finishing = true;
cout << "\nSent flag to stop threads and wait for threads to finish for 1 second";
this_thread::sleep_for(chrono::seconds(1));
for (int i = 0; i < vecSock.size(); ++i)
{
cout << "\nSocket " << i << " opened =\t" << vecSock[i]->is_open();
vecSock[i]->cancel();
vecSock[i]->close();
cout << "\nSocket " << i << " counter =\t" << vecSock[i].use_count();
cout << "\nSocket " << i << " opened =\t" << vecSock[i]->is_open();
vecSock[i].reset();
cout << "\nSocket " << i << " counter =\t" << vecSock[i].use_count();
cout << "\n";
}
this_thread::sleep_for(chrono::seconds(1));
vecSock.clear();
vecSock.resize(4);
vecEndpoint.resize(4);
for (int i = 0; i < 4; ++i)
{
vecSock[i].reset(new boost::asio::ip::udp::socket(io_service_, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), ports[i])));
}
cout << "\nvecSock=4 created";
}
catch (boost::exception& e)
{
cerr <<"\n\a\a"<< boost::diagnostic_information(e);
system("pause");
}
return 0;
}
This causes an binding error (exeption) which i have redirected to console with try-catch.
Throw location unknown (consider using BOOST_THROW_EXCEPTION) Dynamic
exception type: class boost::exception_detail::clone_impl > std::exception::what: bind: Usually are
allowed only one usage of each socket address (Protocol/network
address/port)
Can ony one help? I have tried all, what I could find in references c++ and boost and nothing helped this error.

Related

Sharing a class between threads

I have a class called "Vector", which by default holds 10.000 elements, which at all times must have the same value. This class is tested and works. Therefore I use the method setAndTest() from the class to set the value of all elements, which then immediately checks whether the Vector object is consistent (that all vector elements hold the same value).
In a new file "main.cpp", i have created two functions: writer() and main().
writer() creates a user-defined number of writer threads (between 1 & 100), each with their own unique id. Each writer sets and tests the shared Vector object to its id every second. If a writer detects an inconsistensy in a shared Vector object, setAndTest() returns false and the following error message should be printed: Error with thread #id
However, in 99% of the cases it prints Success with thread #id, whereas I expected that there would be more variation between the two.
Headers included in main.cpp file:
#include <iostream>
#include "Vector.hpp"
#include <pthread.h>
#include <unistd.h>
using namespace std;
Vector object and writer() function:
Vector VecObj; //The Vector object (Defined in global scope)
void* writer(void *threadid)
{
int threadid_ = *(int *)(threadid);
if(VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << endl;
}else
{
std::cout << "\nError with thread " << threadid_ << endl;
}
return NULL;
}
main function:
int main()
{
start:
int numOfThreads = 1;
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if(0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << endl;
}else{
std::cout << "Amount of threads must be between 1 & 100" << endl;
goto start;
}
pthread_t threadcreator[numOfThreads];
for(int i = 0; i < numOfThreads; i++){
pthread_create(&threadcreator[i], NULL, writer, &i);
sleep(1);
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
}
Vector Class (Vector.hpp):
#ifndef VECTOR_HPP_
#define VECTOR_HPP_
#include <pthread.h>
using namespace std;
//=======================================================
// Class: Vector
// contains a size_-size vector of integers.
// Use the function setAndTest to set all elements
// of the vector to a certain value and then test that
// the value is indeed correctly set
//=======================================================
class Vector
{
public:
Vector(unsigned int size = 10000) : size_(size)
{
vector_ = new int[size_];
set(0);
}
~Vector()
{
delete[] vector_;
}
bool setAndTest(int n)
{
set(n);
return test(n);
}
private:
void set(int n)
{
for(unsigned int i=0; i<size_; i++) vector_[i] = n;
}
bool test(int n)
{
for(unsigned int i=0; i<size_; i++) if(vector_[i] != n) return false;
return true;
}
int* vector_;
unsigned int size_;
};
#endif
You are passing each thread a pointer to the same int variable. That variable changes value on each loop iteration. writer() is expecting to receive the same int value that was given to pthread_create(), but that is not guaranteed in your code, even with the sleep() call.
To pass the int correctly, pass the actual int value itself rather than a pointer to the int, eg:
#include <iostream>
#include <vector>
#include <cstdint>
#include <pthread.h>
#include "Vector.hpp"
Vector VecObj;
void* writer(void *arg)
{
int threadid_ = static_cast<int>(reinterpret_cast<intptr_t>(arg));
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
pthread_create(&threadcreator[i], NULL, writer, reinterpret_cast<void*>(i));
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
If you really want to use int* pointers, then you will have to allocate a separate int for each thread, eg:
#include <iostream>
#include <vector>
#include <pthread.h>
#include "Vector.hpp"
Vector VecObj;
void* writer(void *arg)
{
int threadid_ = *static_cast<int*>(arg);
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
std::vector<int> threadids(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
threadids[i] = i;
pthread_create(&threadcreator[i], NULL, writer, &threadids[i]);
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
Or, if you really want to pass an int* pointer to a single int, use a std::conditional_variable or other waitable signal to make sure that each thread has actually captured the int value before allowing the loop to change its value, eg:
#include <iostream>
#include <vector>
#include <conditional_variable>
#include <mutex>
#include "Vector.hpp"
#include <pthread.h>
Vector VecObj;
std::condition_variable cv;
std::mutex cv_m;
bool captured = false;
void* writer(void *arg)
{
int threadid_;
{
std::lock_guard<std::mutex> lk(cv_m);
threadid_ = *static_cast<int*>(arg);
captured = true;
}
cv.notify_one();
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
std::unique_lock<std::mutex> lk(cv_m);
captured = false;
pthread_create(&threadcreator[i], NULL, writer, &i);
cv.wait(lk, [](){ return captured; });
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
UPDATE: oh, now I see another major problem. You have multiple threads writing to, and reading from, a single Vector object in memory without synchronization. That is not safe to do. While one thread is reading from an element in the Vector's array, another thread can be writing a new value to that same element, and there is no guarantee that the element will remain consistent across both operations. You MUST synchronize access to the Vector object since it is being shared across multiple threads, eg:
...
#include <mutex>
...
Vector VecObj;
std::mutex vec_m;
...
void* writer(void *threadid)
{
int threadid_ = ...;
bool testResult;
{
std::lock_guard lk(vec_m);
testResult = VecObj.setAndTest(threadid_);
}
if (testResult)
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
...

Single producer / multiple consumer deadlock

The following code reasults in a deadlock. The problem is that I cannot figure out how unlock the consumers waiting on the condition variable. The consumer should loop and consume from the stack when a certain condition is met. I've tried exiting when the stack is empty but of course it doesn't work.
Stack.h
class Stack {
private:
std::stack<int> stack;
std::mutex mutex;
std::condition_variable is_empty;
bool done;
public:
Stack();
void push(int);
void pop();
void print();
bool isDone() const;
~Stack();
};
Stack.cpp
#include <iostream>
#include <sstream>
#include <thread>
#include "Stack.h"
void Stack::push(int x) {
std::lock_guard lock(mutex);
std::stringstream msg1;
msg1 << "producer " << std::this_thread::get_id() << " pushing " << x << std::endl;
std::cout << msg1.str();
stack.push(x);
std::stringstream msg;
msg << "producer " << std::this_thread::get_id() << ": " << x << " pushed" << std::endl;
std::cout << msg.str();
is_empty.notify_all();
}
void Stack::pop() {
std::unique_lock lock(mutex);
std::stringstream msg;
msg << "consumer " << std::this_thread::get_id() << " waiting to consume" << std::endl;
std::cout << msg.str();
is_empty.wait(lock, [this] { return !stack.empty(); });
if (!stack.empty()) {
stack.pop();
std::stringstream msg1;
msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
std::cout << msg1.str();
} else {
done = true;
is_empty.notify_all();
}
}
void Stack::print() {
std::lock_guard lock(mutex);
for (int i = 0; i < stack.size(); i++) {
std::cout << "\t" << stack.top() << std::endl;
}
}
Stack::~Stack() {
}
bool Stack::isDone() const {
return done;
}
Stack::Stack() : done(false) {}
main.cpp
#include <thread>
#include <vector>
#include <iostream>
#include "Stack.h"
int main() {
Stack stack;
std::vector<std::thread> producer;
std::vector<std::thread> consumer;
for (int i = 0; i < 10; i++) {
consumer.emplace_back([&stack]{
while (!stack.isDone()) {
stack.pop();
}
});
}
for (int i = 0; i < 1; i++) {
producer.emplace_back([&stack]{
for (int j = 0; j < 5; ++j) {
stack.push(random());
}
});
}
for (int k = 0; k < producer.size(); k++) {
producer[k].join();
std::cout << producer[k].get_id() << " joined" << std::endl;
stack.print();
}
for (int j = 0; j < consumer.size(); j++) {
consumer[j].join();
std::cout << consumer[j].get_id() << " joined" << std::endl;
stack.print();
}
return 0;
}
Your code is not deadlocked but your threads are waiting for more input because you haven't configure the value of done properly.
There is no way that the else condition is invoked here
is_empty.wait(lock, [this] { return !stack.empty(); });
if (!stack.empty()) {
stack.pop();
std::stringstream msg1;
msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
std::cout << msg1.str();
} else {
done = true;
is_empty.notify_all();
}
Looking from the code it seems like what you want is that after the producer stops producing the consumer should wake up and empty. But this is not the way to implement it. After the producer has pushed 5 elements you should set done =true from there.
Also as answered by madducci you need to change the location of notify_all();
This is something which worked for me
is_empty.wait(lock, [&] { return stack.size()>0 || done; });
if (!stack.empty()) {
int val=stack.top();
stack.pop();
std::stringstream msg1;
msg1 << "consumer " << std::this_thread::get_id() << " popped " <<val<<std::endl;
std::cout << msg1.str();
}
Looks like you have a logic error in your pop function: you never call notify_all() in case you pop an element from the stack.
The correct way should be this one:
void Stack::pop() {
std::unique_lock lock(mutex);
std::stringstream msg;
msg << "consumer " << std::this_thread::get_id() << " waiting to consume" << std::endl;
std::cout << msg.str();
is_empty.wait(lock, [this] { return !stack.empty(); });
if (!stack.empty()) {
stack.pop();
std::stringstream msg1;
msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
std::cout << msg1.str();
} else {
done = true;
}
is_empty.notify_all();
}
You also invoke pop() before push() in your main

Passing a variable through signal and slot system in Qt [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
So I want to pass a std::string variable through the signal and slot system in Qt; I have a class on heap called RecordTalks which emits a signal when received message from chat is longer than 25 signs.
The code is as follows:
#include "recordtalks.h"
// records chat to files RecordTalks::RecordTalks(QObject *parent) {
}
RecordTalks::~RecordTalks() {
std::cout << "destructor" << "\n"; }
void RecordTalks::run(QString data) {
std::cout << ">>> whole data is: " << data.toStdString() << " ------------------\n";
std::string text = data.toStdString();
extractNick(text);
extractRoom(text);
//std::cout << "save in recordTalks is: " << save << "\n";
if((nick.size()!=0 && room.size()!=0))
{
extractText(data);
pushToVector(removeDigitsAndSpecials(nick), subText);
}
else
return; }
void RecordTalks::run() {
save=false;
save = console.saveNowState();
if(save==true)
{
saveToFile(allTexts, "BOT"); //trigger line saving to file
file.close();
removeDuplicatedNicks();
createNickFiles(nicks_v);
match_nicks_and_allTexts(allTexts);
closeNickFiles();
nicks_v.clear();
nickAndFile_pair_vec.clear();
text.clear();
allTexts.clear();
nick.clear();
room.clear();
subText.clear();
save=false;
}
}
void RecordTalks::extractText(QString &data) {
std::string text = data.toStdString(); // tu zmiana
size_t pos, pos2;
if((pos=text.find("PRIVMSG #"))!=std::string::npos)
{
if((pos2=text.find(":",pos))!=std::string::npos)
{
subText = text.substr(pos2+1, text.size()-(pos2+1) );
if((pos=subText.find("\u0001ACTION "))!=std::string::npos)
{
subText = subText.substr(pos+8 , subText.size()-3-(pos+8));
}
else
std::cout << "subText: " << subText << "\n";
}
}
else //if nothing to write to log:
{
return ;
}
}
void RecordTalks::extractNick(std::string &text) {
Extract_NickAndRoom e;
QString temp = QString::fromStdString(text);
nick = e.extractNick(temp);
//std::cout << "nick is: " << nick << "\n";
}
void RecordTalks::extractRoom(std::string &text) {
Extract_NickAndRoom e;
QString temp = QString::fromStdString(text);
room = e.extractRoom(temp);
//std::cout << "room is: " << room << "\n"; }
void RecordTalks::pushToVector(std::string nick, std::string &subText)
//general vector with texts {
if(subText.size()>25 ) //if line of text from irc is bigger than 25 signs
{
std::pair<std::string, std::string> para = std::make_pair(nick, subText);
allTexts.push_back(para); // pair --> vector
emit textUpdateSignal(subText);
std::cout << "EMITTTTTTTTTTTTTTTTTTT " << "\n";
//std::cout << ">>> subText: " << subText << " nick: " << nick << " <<<" << "\n";
}
if(allTexts.size()==60)
{
saveToFile(allTexts, "BOT"); //trigger line saving to file
file.close();
removeDuplicatedNicks();
createNickFiles(nicks_v);
match_nicks_and_allTexts(allTexts);
closeNickFiles();
nicks_v.clear();
nickAndFile_pair_vec.clear();
text.clear();
allTexts.clear();
nick.clear();
room.clear();
subText.clear();
save=false;
}
}
void RecordTalks::saveToFile( std::vector< std::pair<std::string,
std::string> > &allTexts, std::string nickFileName) {
std::string address = "D:\\Qt_workspace\\weatherBot\\logs\\" + nickFileName + ".txt";
file.open(address, std::ios::out | std::ios::app);
for (int i = 0; i < allTexts.size(); ++i)
{
file << allTexts[i].second; //writes text to file, not the nicks
}
}
void RecordTalks::createNickFiles(std::vector<std::string> &nicks_v) {
/* make vector of pair nick and file, so we can identify the file name and then
put text-matching-to-file-nick with file name */
for (int i = 0; i < nicks_v.size(); ++i)
{
std::fstream file2("D:\\Qt_workspace\\weatherBot\\logs\\"+ nicks_v[i] + ".txt",
std::ios::out | std::ios::app);
std::pair<std::string, std::fstream> nickAndFile_pair;
nickAndFile_pair = std::make_pair(removeDigitsAndSpecials(nicks_v[i]),
std::move(file2));
nickAndFile_pair_vec.push_back(std::move(nickAndFile_pair));
}
}// nicks_v[i] put inside function removeDigitsAndSpecials(std::string& nick)
void RecordTalks::match_nicks_and_allTexts(std::vector<
std::pair<std::string, std::string> > allTexts) {
for (int i = 0; i < nickAndFile_pair_vec.size(); ++i)
{
for (int j = 0; j < allTexts.size(); ++j)
{
if(nickAndFile_pair_vec[i].first == allTexts[j].first)
{
nickAndFile_pair_vec[i].second << allTexts[j].second;
//nickAndFile_pair_vec[j].second.flush();
}
}
}
std::cout << "allTexts size in match_nicks_and_allTexts is: ";
std::cout << allTexts.size() << "\n";
}
void RecordTalks::removeDuplicatedNicks() {
std::vector< std::pair<std::string, std::string> > temp = allTexts;
std::cout << "temp size: " << temp.size() << "\n";
for (int i = 0; i < temp.size(); ++i)
{
for (int j = i+1; j < temp.size(); ++j)
{
if(temp[i].first == temp[j].first && i+1< temp.size())
{
temp.erase(temp.begin()+j);
j--;
}
}
}
for (int i = 0; i < temp.size(); ++i)
{
nicks_v.push_back(temp[i].first);
}
std::cout << "nicks_v.size: " << nicks_v.size() << "\n";
}
void RecordTalks::closeNickFiles() //closes separate nick files {
for (int i = 0; i < nickAndFile_pair_vec.size(); ++i)
{
nickAndFile_pair_vec[i].second.close();
}
std::cout << "Files closed..." << "\n"; }
std::string RecordTalks::removeDigitsAndSpecials(std::string& nick) {
for (int i = 0; i < nick.size(); ++i)
{
if(std::isalpha(nick[i]))
{
}
else if(std::isdigit(nick[i]))
{
nick.erase(nick.begin()+i);
std::cout << "removing: " << nick[i] << "\n";
i--;
}
else
{
nick.erase(nick.begin()+i);
std::cout << "removing: " << nick[i] << "\n";
i--;
}
}
return nick;
}
Then in another class i have the connect function. When i write it in this form:
connect(recordTalks, &RecordTalks::textUpdateSignal, this, &Socket::updateDatabaseSLOT);
the slot receives the signal. But when i write the function this way:
connect(recordTalks, SIGNAL(textUpdateSign(std::string)), this,
SLOT(updateDatabaseSLOT(std::string)));
the Slot is not fired. So my question is, what is the reason of that. In other cases the latter version works just fine.
The slot looks like this:
void Socket::updateDatabaseSLOT(std::string textUpdate)
{
std::cout << "updates text: << textUpdate << "\n";
database.push_back(textUpdate);
}
I think you have a typo in your connect statement. Qt can be frustrating that way. SIGNAL(textUpdateSign(std::string ) should probably be SIGNAL(textUpdateSignal(std::string ).

pthread on MinGW 32 with eclipse 64 bit

I have MinGW32 and building a small piece of code using pthread on eclipse. The code compiles and links successfully, but terminates on running it with a non zero exit value. There are no warnings around this.However, on debugging it,it works fine. Pls advice.
#include <iostream>
#include <pthread.h>
using namespace std;
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
void* increment(void* counter)
{
cout << "increment" << endl;
int* pcounter = (int*)counter;
for(int i =0; i < 30000; ++i)
{
cout << "Inside for loop" << endl;
pthread_mutex_lock(&counter_mutex);
++(*pcounter);
pthread_mutex_unlock(&counter_mutex);
}
}
int main()
{
pthread_t arr[5];
int counter =0;
for(int i=0; i < 5; ++i)
{
cout << "Creating thread: " << i << endl;
int rc = pthread_create(&arr[i], NULL, increment, (void*)&counter);
if(rc != 0)
{
cout << "Error creating thread: " << rc << endl;
exit(0);
}
}
for(int i=0; i < 5 ; ++i)
{
pthread_join(arr[i], NULL);
}
cout << "result: " << counter << endl;
return 0;
}

swapcontext. What's meaning of field uc_stack in struct ucontext_t?Who use it? The coroutine or the coroutine's signal handler? How can I test it?

What's meaning of field uc_stack in struct ucontext_t?Who use it? The coroutine or the coroutine's signal handler? How can I test it? For example
#include <iostream>
#include <ucontext.h>
#include <queue>
#include <signal.h>
using namespace std;
void sigHandler(int signo)
{
printf("sigHandler:%x\n", &signo);
exit(-1);
}
queue<int> qProduct;
void consumer(ucontext_t* pConsumer, ucontext_t* pProducer)
{
char a[SIGSTKSZ] = {0};
while(1)
{
if(qProduct.size() > 0)
{
cout << __FUNCTION__ << "|" << qProduct.front() << endl;
qProduct.pop();
}
else
{
cout << pConsumer << "|" << pProducer << endl;
swapcontext(pConsumer, pProducer);
}
}
}
void producer(ucontext_t* pConsumer, ucontext_t* pProducer, bool* pFinished)
{
for(int i=0; i<10; i++)
{
if(qProduct.size() < 5)
{
qProduct.push(i);
cout << __FUNCTION__ << "|" << i << endl;
}
else
{
cout << pConsumer << "|P|" << pProducer << endl;
swapcontext(pProducer, pConsumer);
}
}
cout << pConsumer << "|P|" << pProducer << endl;
swapcontext(pProducer, pConsumer);
*pFinished = true;
}
int main(int argc, char* argv[])
{
ucontext_t Main, Consumer, Producer;
/* The stack for the iterator function. */
char consumer_stack[SIGSTKSZ];
char producer_stack[SIGSTKSZ];
cout << "SIGSTKSZ:" << SIGSTKSZ << endl;
/* Flag indicating that the iterator has completed. */
volatile bool bFinished = false;
getcontext(&Consumer);
Consumer.uc_link = &Main;
Consumer.uc_stack.ss_sp = consumer_stack;
Consumer.uc_stack.ss_size = sizeof(consumer_stack);
makecontext(&Consumer, (void (*)(void))consumer, 2, &Consumer, &Producer);
getcontext(&Producer);
Producer.uc_link = &Main;
Producer.uc_stack.ss_sp = producer_stack;
Producer.uc_stack.ss_size = sizeof(producer_stack);
makecontext(&Producer, (void (*)(void))producer, 3, &Consumer, &Producer, &bFinished);
if(!bFinished)
{
swapcontext(&Main, &Producer);
}
return 0;
}
Who use the stack "consumer_stack", "consumer" or "sigHandler"?How to prove it?