I am writting an OpevCV program,a multi-thread program,one of threads should receive alarm signal.It's a little complicated.To show where the problem is,i wrote the test code,like below:
MainThread:
int main(int argc,char **argv)
{
cout << "main thread = " << pthread_self() << endl;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_BLOCK, &set, NULL);
struct sigaction sa;
sa.sa_handler = int_handler;
sa.sa_flags |= SA_INTERRUPT;
sigaction(SIGALRM,&sa,NULL);
pthread_t thread;
if(pthread_create(&thread, NULL, capturePictures, NULL) < 0)
{
cerr << "pthread_create error" << endl;
return -1;
}
alarm(5);
pthread_join(thread, NULL);
return 0;
}
ChildThread:
void *capturePictures(void* arg)
{
cout << "capturePictures thread = " << pthread_self() << endl;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
string rtsp = "rtsp://admin:admin12345#192.168.0.81:554/h264/cha1/main/av_stream";
VideoCapture vcap;
if(!vcap.open(rtsp)) {
cout << "open stream error" << endl;
return (void *)-1;
}
unsigned int picIndex = 0;
int index = 0;
Mat image;
while(1){
if (!vcap.read(image)){
cout <<"read image error" << endl;
return (void*)-1;
}
if (picIndex++ % 25 != 0) continue;
char fileName[30];
sprintf(fileName,"pictures/%d.jpg",++index);
imwrite(fileName, image);
}
}
int_handler:
void int_handler(int signum)
{
cout << "int_handler = " << pthread_self() << endl;
}
This test code doesn't mean anthing,just want to show you where the problem is.
The output is like this:
main thread = 140334223800320
capturePictures thread = 140333923575552
int_handler = 140333931968256
int_handler isn't called in main thread nor capturePictures thread(child thread),i don't even know which thread's id is 140333931968256,i just create one child thread...
If i want to achieve my goal,how can i do?
Related
I have a code, main thread create 2 thread(thread_1 and thread_2), I use pthread_cancel to cancel thread_1 in thread_2, but the data that I create in thread_1 will not be destructored when I run it in QNX system, but there is no problem in Linux system.
It my test code, when I run it in QNX system,MyClass and MyClass2 object destructor not be called, so the 100M memory will leak; but run it in Linux system,it will call MyClass and MyClass2 object destructor. why is there such a difference???
#include <iostream>
#include <pthread.h>
#include <thread>
using namespace std;
pthread_t thread_id_1;
pthread_t thread_id_2;
class MyClass2
{
public:
MyClass2() {
cout << "Build MyClass2" << endl;
}
~MyClass2() {
cout << "Destory MyClass2" << endl;
}
};
class MyClass
{
public:
MyClass() {
cout << "Build MyClass" << endl;
p = (char *)malloc(1024 * 1024 *100);
}
~MyClass() {
cout << "Destory MyClass" << endl;
free(p);
}
char *p;
};
void func(int i)
{
MyClass2 c2;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
cout << "thread 1 func:" << i << endl;
}
static void *thread_1(void *arg)
{
MyClass my_class;
int type_value = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
cout << "thread_1 set cancle type+++++:" << type_value << endl;
for (int i = 0; i < 10; i++) {
func(i);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return nullptr;
}
static void *thread_2(void *arg)
{
for (int i = 0; i < 10; i++) {
cout << "thread_2:" << i << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
int ret = pthread_cancel(thread_id_1);
cout << "otx_thread_2 cancel thread 1 ret:" << ret << endl;
return nullptr;
}
int main(int argc, char *argv[])
{
cout << "Main start" << endl;
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
cout << "Main set detch" << endl;
if (pthread_create(&thread_id_1, &attr, thread_1, nullptr) != 0) {
cout << "pthread_create() 1 error" << endl;
return -1;
}
if (pthread_create(&thread_id_2, nullptr, thread_2, nullptr) != 0) {
cout << "pthread_create() 2 error" << endl;
return -1;
}
if (pthread_join(thread_id_2, NULL) != 0) {
cout << "pthread_join() 1 error";
return -1;
}
while (1) {
cout << "Main Loop" << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
enter image description here
enter image description here
I try it again and again, so I confirm that there is no problem with the code, But I don't understand why there is such a difference
pthread_cancel is outside the scope of the C++ specification. C++ does not specify its behavior, nor inherit it from C or POSIX.
The difference is simply because QNX and Linux have implemented pthread_cancel differently in a C++ environment. There is literally nothing more to it than that.
I imagine that the QNX implementation stops the thread in its tracks, whereas the Linux implementation probably induces an exception which unwinds the canceled thread's stack.
my project use three Level process mode. In order to the code after the fork does not inherit from the worker thread of the previous process, so create sub thread to fork sub process when each called.
Now, I found some problems at following describe:
1. the grandson process create a std::thread(work_thread), when called the join() method, it's throw a exception
2. if the son process dose not in sub thread call fork() method, then it's does not thow exception
3. if in grandson process create a empty std::thread(it's nothing to do) before the work thread create, and the empty thread called join() method after the work thread called join() , then it is does not throw the exception. but if the empty thread called join() before work thread, it's also throw the same exception
if you can help me, please write your answer, i will thank you very much
the following code is test case:
#include <iostream>
#include <unistd.h>
#include <wait.h>
#include <thread>
using namespace std;
int main(int argc, char **argv)
{
std::thread t([]() {
int l2pid = fork();
if(l2pid > 0)
waitpid(l2pid, NULL, 0);
else if (l2pid == 0)
{
std::thread t2([]() {
int l3pid = fork();
if (l3pid > 0)
waitpid(l3pid, NULL, 0);
else if (l3pid == 0){
//std::thread empty_thread([](){
//});
std::thread work_thread([](){
for(int i = 0; i < 5; i++){
std::cout << "working..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
if(work_thread.joinable())
work_thread.join();
//if(empty_thread.joinable())
// empty_thread.join();
std::cout << "L3 Process Exit!" << std::endl;
}
});
if (t2.joinable())
t2.join();
std::cout << "L2 Process Exit!" << std::endl;
}
});
if (t.joinable())
t.join();
std::cout << "Main Process Exit!" << std::endl;
return 0;
}
i use pthread_create and pthread_join also return EDEADLK
#include <iostream>
#include <unistd.h>
#include <wait.h>
#include <thread>
#include <vector>
#include <pthread.h>
using namespace std;
void *work_thread(void *)
{
for (int i = 0; i < 5; i++)
{
std::cout << "working..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return NULL;
}
void *t2_function(void *)
{
int l3pid = fork();
if (l3pid > 0)
{
waitpid(l3pid, NULL, 0);
}
else if (l3pid == 0)
{
pthread_t thread_handle;
int ret = pthread_create(&thread_handle, NULL, work_thread, NULL);
std::this_thread::sleep_for(std::chrono::seconds(3));
void *pthread_ret = NULL;
std::cout << "thread_handle:" << thread_handle << ",pthread_self:" << pthread_self() << std::endl;
ret = pthread_join(thread_handle, &pthread_ret);
std::cout << "pthread_join:" << ret << std::endl;
std::cout << "L3 Process Exit!" << std::endl;
}
}
void * t1_function(void *)
{
int l2pid = fork();
if (l2pid > 0)
waitpid(l2pid, NULL, 0);
else if (l2pid == 0)
{
pthread_t l2;
pthread_create(&l2, NULL, t2_function, NULL);
pthread_join(l2, NULL);
std::cout << "L2 Process Exit!" << std::endl;
}
}
int main(int argc, char **argv)
{
pthread_t l1;
pthread_create(&l1, NULL, t1_function, NULL);
pthread_join(l1, NULL);
std::cout << "L1 Process Exit!" << std::endl;
return 0;
}
I am using GLib for the first time. So, to understand how to use GLib APIs, I wrote following dummy program.
#include<glib.h>
#include<iostream>
#include<thread>
#include<chrono>
using namespace std;
using namespace std::chrono_literals;
class executor
{
private:
GMainLoop* main_loop;
GMainContext* worker_context;
thread worker_thread;
void worker_loop()
{
g_main_context_push_thread_default(worker_context);
cout << "Starting main loop" << endl;
g_main_loop_run(main_loop);
cout << "Finished main loop" << endl;
g_main_context_pop_thread_default(worker_context);
}
public:
executor()
{
worker_context = g_main_context_new();
main_loop = g_main_loop_new(worker_context, false);
worker_thread = thread(&executor::worker_loop, this);
}
~executor()
{
g_main_loop_quit(main_loop);
cout << "Stopped main loop from running" << endl;
g_main_loop_unref(main_loop);
g_main_context_unref(worker_context);
if (worker_thread.joinable())
{
worker_thread.join();
}
}
void queue_callback(int (*callback)(void))
{
GSource* idle_source = g_idle_source_new();
g_source_set_callback(idle_source, (GSourceFunc)callback, NULL, NULL);
g_source_attach(idle_source, worker_context);
g_source_unref(idle_source);
}
};
int func1()
{
cout << "func1 started" << endl;
this_thread::sleep_for(5s);
cout << "func1 finished waiting" << endl;
return 0;
}
int func2()
{
cout << "func2 started" << endl;
this_thread::sleep_for(1s);
cout << "func2 finished waiting" << endl;
return 0;
}
int main()
{
executor e;
e.queue_callback(func1);
e.queue_callback(func2);
return 0;
}
When I run the program, it does not finish executing, it gets stuck. This is the output it prints.
Stopped main loop from running
Starting main loop
func1 started
func1 finished waiting
func2 started
func2 finished waiting
Sometimes it just fails with following error
Stopped main loop from running
Starting main loop
(process:16343): GLib-CRITICAL **: 10:58:54.405: g_main_loop_run: assertion 'g_atomic_int_get (&loop->ref_count) > 0' failed
Finished main loop
My guess is these both problems are happening because g_main_loop_quit and g_main_loop_unref run before g_main_loop_run. How do I fix these issues?
EDIT after user7860670's comment:
Thanks to user7860670 for the suggestion. Here is the working code now.
#include<glib.h>
#include<iostream>
#include<thread>
#include<chrono>
using namespace std;
using namespace std::chrono_literals;
class executor
{
private:
GMainLoop* main_loop;
GMainContext* worker_context;
thread worker_thread;
void worker_loop()
{
g_main_context_push_thread_default(worker_context);
cout << "Starting main loop" << endl;
g_main_loop_run(main_loop);
cout << "Finished main loop" << endl;
g_main_context_pop_thread_default(worker_context);
}
public:
executor()
{
worker_context = g_main_context_new();
main_loop = g_main_loop_new(worker_context, false);
worker_thread = thread(&executor::worker_loop, this);
}
~executor()
{
cout << "Stopping main loop" << endl;
GSource* idle_source = g_idle_source_new();
g_source_set_callback(idle_source, (GSourceFunc)g_main_loop_quit, main_loop, NULL);
g_source_attach(idle_source, worker_context);
g_source_unref(idle_source);
if (worker_thread.joinable())
{
worker_thread.join();
}
cout << "Removing references to main loop and context" << endl;
g_main_loop_unref(main_loop);
g_main_context_unref(worker_context);
}
void queue_callback(int (*callback)(void))
{
GSource* idle_source = g_idle_source_new();
g_source_set_callback(idle_source, (GSourceFunc)callback, NULL, NULL);
g_source_attach(idle_source, worker_context);
g_source_unref(idle_source);
}
};
int func1()
{
cout << "func1 started" << endl;
this_thread::sleep_for(5s);
cout << "func1 finished waiting" << endl;
return 0;
}
int func2()
{
cout << "func2 started" << endl;
this_thread::sleep_for(1s);
cout << "func2 finished waiting" << endl;
return 0;
}
int main()
{
executor e;
e.queue_callback(func1);
e.queue_callback(func2);
return 0;
}
It looks like executor e; may go out of scope prior to worker thread starting to work and since at the ~executor() you are unrefing loop and context objects prior to waiting for worker thread their reference count drops to 0 and they are getting destroyed prior to working thread working. You should do it other way around: wait for a worker thread to finish and only then unref loop and context objects.
I have some questions regarding the use of SIGINT and SIGTSTP in relation to managing processes in my own unix shell. But first of the code here:
void execute(vector<char *> argvv, bool x){
pid_t pid;
int status;
int error;
pid = fork();
a = pid;
argvv.push_back(NULL);
if(pid == -1){
cout << "error" << endl;
}else if(pid == 0){
error = execvp(argvv[0],argvv.data());
if(error == -1){
exit(-1);
}
// In Child Process
}else{
// If no "&", then wait for process
if(x == false){
if(wait(&status) != pid){
perror("wait()");
}
}else{
cout << "Pid des Hintergrundprozesses: " << pid << endl;
}
// in parent process
}
}
This function just receives the entered operation and parameters, forks a new process and executes it.
Now my signalhandler functions:
void signalHandlerSigInt(int signum){
cout << "Interrupt Signal (" << signum <<") received." << endl;
kill(a,SIGINT);
cout << "Killed Process: " << a << endl;
}
void signalHandlerSigTStp(int signum){
cout << "Interrupt Signal (" << signum <<") received." << endl;
kill(a,SIGTSTP);
cout << "Stop process..: " << a << endl;
}
and my main.cpp:
int main(int agc, char** argv) {
bool opBackground;
string operation;
vector<string> arguments;
vector<char *> argvv(arguments.size() + 1);
signal(SIGINT, signalHandlerSigInt);
signal(SIGTSTP, signalHandlerSigTStp);
while(true){
cout << "myshell>";
getline(cin,operation);
if(operation == "logout"){
logout();
}else{
opBackground = befehlUebersetzen(operation, &arguments);
vector<char *> argvv(arguments.size() + 1);
for(size_t i = 0; i != arguments.size(); ++i){
argvv[i] = &arguments[i][0];
}
execute(argvv, opBackground);
arguments.clear();
}
}
return 0;
}
The shell itself works fine, I now need to extend it to be able to kill the foreground process by pressing CTRL+C or stop the process with CTRL+Z.
I think I understood what a Signalhandler does, but is kill(a,SIGINT) the right way to transmit the signal SIGINT to my process? ("a" is a global variable for my forked pid, that means the last process I forked).
My problem is, when starting a process in the background and then start another process in the foreground it kills both processes when pressing CTRL+C.
Also the SIGTSTP signalhandler doesnt seem to work at all (does nothing - process just keeps running in the foreground).
Am I completely wrong with what im doing?
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?