请教Linux多线程的问题

karen99 2015-11-27 11:58:05
这是我给分最多的一个帖子了,希望得到大家的帮助!

问题其实特别简单,我想用Linux创建两个线程,一个线程用来显示一个视频,另一个线程用来搜集键盘输入,当键盘输入为Q时,退出视频显示;当输入问其他键时,做其他处理。

当然这个简单的任务不需要用两个线程来完成,只是想了解多线程编程的有关知识,所以用这个来做简单的例子。感谢大家的耐心。

还有一个问题就是pthread_create()函数参数传递的问题,这个函数输入的第四个参数可以用来传递参数进入这个函数;如果在函数中改变这个参数的值,能不能在退出时读取这个参数就得到这个线程的输出呢?另一个方法输出线程参数是pthread_exit(参数),可是这两种方法好像都不成功,就是说返回的值都不是期望的。不知道什么才是正确的传递参数进出线程的方法呢?

先谢谢大家!期待大家的回复!

...全文
281 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
karen99 2015-12-03
  • 打赏
  • 举报
回复
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; Mat frame; Mat keyBoardInput = imread("keyboard_input.png",1); Mat menu = imread("menu.png",1); VideoCapture cap(0); struct Para { Mat captureImage; char keyInput; char winName[3]; }; pthread_mutex_t dispwindow; void *GUI_Thread(void * param) { //Mat keyBoardInput = imread("keyboard_input.png",1); Para *p_data = (Para *)param; while(p_data->captureImage.rows>0 && p_data->captureImage.cols>0) { pthread_mutex_lock (&dispwindow); imshow("ppp",p_data->captureImage); int key_input=cv::waitKey(30)%256; if(key_input == 'q' || key_input == 'Q' ) { p_data->keyInput = key_input; break; } else if(key_input == 'd' || key_input == 'D' || key_input == 'L' || key_input == 'l' || key_input == 13 || key_input == 43)//13 enter; 43 +; { p_data->keyInput = key_input; } pthread_mutex_unlock (&dispwindow); } printf("GUI_Thread exited.\n"); pthread_exit(0); return NULL; } void * Capture_Display_Thread(void * param) { Para *p_data = (Para *)param; char key_input; long exit_code = 0; // VideoCapture cap(0); if(!cap.isOpened()) // check if we succeeded { exit_code = -2; } //pthread_mutex_lock (&dispwindow); while( p_data->keyInput != 'q' && p_data->keyInput != 'Q') { printf("\n displaying Video\n"); cap >> frame; // get a new frame from camera if((frame.rows > 0) && (frame.cols > 0)) { pthread_mutex_lock (&dispwindow); Mat disp = frame.clone(); if(p_data->keyInput == 'd' || p_data->keyInput == 'D') { for(int i=100;i<200;i++) { for(int j=100;j<200;j++) { disp.at<Vec3b>(i,j)[0] = 255; disp.at<Vec3b>(i,j)[1] = 255; disp.at<Vec3b>(i,j)[2] = 255; } } } if(p_data->keyInput == 'l' ||p_data->keyInput == 'L') { //Mat menu = imread("menu.png",1); menu.copyTo(disp(Rect(30,30,menu.cols,menu.rows))); } p_data->captureImage = disp.clone(); cv::imshow("ppp", disp); pthread_mutex_unlock (&dispwindow); } waitKey(30); } //pthread_mutex_unlock (&dispwindow); printf("stopped.\n"); pthread_exit((void *)exit_code); return NULL; } int main(int argc, char * argv[]) { Para mydata; pthread_t display,gui; void * exit_disp = NULL; void * exit_gui = NULL; pthread_mutex_init(&dispwindow, NULL); printf("start...\n"); int rc = pthread_create(&gui, NULL, GUI_Thread, (void *)&mydata); rc = pthread_create(&display, NULL, Capture_Display_Thread, (void *)&mydata); if(0 != rc) return -1; pthread_join(display, &exit_disp); pthread_join(gui, &exit_gui); // printf("gui = %c\n", mydata); pthread_mutex_destroy(&dispwindow); return 0; }
karen99 2015-12-03
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
Mat frame;
	Mat keyBoardInput = imread("keyboard_input.png",1);
	Mat menu = imread("menu.png",1);
	VideoCapture cap(0);
struct Para
{
	Mat captureImage;
	char keyInput;
	char winName[3];
};

pthread_mutex_t dispwindow;
void *GUI_Thread(void * param)
{

	//Mat keyBoardInput = imread("keyboard_input.png",1);
	Para *p_data = (Para *)param;
	
	while(p_data->captureImage.rows>0 && p_data->captureImage.cols>0)
	{
		pthread_mutex_lock (&dispwindow);
			imshow("ppp",p_data->captureImage);
			
			int key_input=cv::waitKey(30)%256;
			

			if(key_input == 'q' || key_input == 'Q' )
			{				
				p_data->keyInput = key_input;				
				break;
			}
			else if(key_input == 'd' || key_input == 'D' || key_input == 'L' || key_input == 'l'
				|| key_input == 13 || key_input == 43)//13 enter; 43 +;
			{	
				p_data->keyInput = key_input;
			}
	
			pthread_mutex_unlock (&dispwindow);
	}
	
    printf("GUI_Thread exited.\n"); 
    pthread_exit(0);
	return NULL;
}

void * Capture_Display_Thread(void * param)
{
    Para *p_data = (Para *)param;


    char key_input;
    long exit_code = 0;
    
//    VideoCapture cap(0);
    if(!cap.isOpened())  // check if we succeeded
    {
        exit_code = -2; 
    }
    
	//pthread_mutex_lock (&dispwindow);
	while( p_data->keyInput != 'q' && p_data->keyInput != 'Q')
    {
        printf("\n displaying Video\n");
        cap >> frame; // get a new frame from camera
		
        if((frame.rows > 0) && (frame.cols > 0))
        {
			pthread_mutex_lock (&dispwindow);
			Mat disp = frame.clone();

			if(p_data->keyInput == 'd' || p_data->keyInput == 'D')
			{
				for(int i=100;i<200;i++)
				{
					for(int j=100;j<200;j++)
					{
						disp.at<Vec3b>(i,j)[0] = 255;
						disp.at<Vec3b>(i,j)[1] = 255;
						disp.at<Vec3b>(i,j)[2] = 255;
					}
				}
				
			}

			if(p_data->keyInput == 'l' ||p_data->keyInput == 'L')
			{
				//Mat menu = imread("menu.png",1);
				
				menu.copyTo(disp(Rect(30,30,menu.cols,menu.rows)));
			}

			p_data->captureImage = disp.clone();
			
            cv::imshow("ppp", disp);
			pthread_mutex_unlock (&dispwindow);

        }

        waitKey(30);
    }
	//pthread_mutex_unlock (&dispwindow);
    printf("stopped.\n");

    pthread_exit((void *)exit_code);
	return NULL;
}

int main(int argc, char * argv[])
{
    Para mydata;
	
    pthread_t display,gui;
    void * exit_disp = NULL;
    void * exit_gui = NULL;
    pthread_mutex_init(&dispwindow, NULL);

    printf("start...\n");
    int rc = pthread_create(&gui, NULL, GUI_Thread, (void *)&mydata);

    rc = pthread_create(&display, NULL, Capture_Display_Thread, (void *)&mydata);

    if(0 != rc) return -1;

    pthread_join(display, &exit_disp);


    pthread_join(gui, &exit_gui); 


//    printf("gui = %c\n", mydata);

	pthread_mutex_destroy(&dispwindow);
    return 0;
}

引用 15 楼 chehw_1 的回复:
也许是你控制视频输入的代码放置的位置不对(比如放在了GUI的消息或事件响应的代码中),使得GUI界面无法刷新(GUI界面必须等你的代码处理完毕,结束上一事件响应后才能刷新)。
karen99 2015-12-02
  • 打赏
  • 举报
回复
非常感谢你的帮助!现在问题都解决了:) 祝好! Karen
引用 15 楼 chehw_1 的回复:
也许是你控制视频输入的代码放置的位置不对(比如放在了GUI的消息或事件响应的代码中),使得GUI界面无法刷新(GUI界面必须等你的代码处理完毕,结束上一事件响应后才能刷新)。 [quote=引用 14 楼 karen99 的回复:] 谢谢你!你的代码我都收藏了,有时间来慢慢学习,现在碰巧我需要一个图像来做GUI,所以就显示那个图像然后用waiKey()来输入命令了,算是暂时解决了这个问题。 想再请教你一个问题,都是多线程里比较基本的问题,再次感谢你的耐心 根据我以上的思路,会有两个图像显示,一个是视频输入,一个是我的用户界面图像,我运行了程序,发现有时候那个用户界面图像很久都不出现。想要的结果是,两个线程都运行一下下,也就是两个图像都能看见了,然后再进入系统自己调度的状态,不知道需要怎么控制线程产生的时间才能达到这个效果,再次感谢您的帮助 [quote=引用 13 楼 chehw_1 的回复:] 如果使用了其他GUI库,很可能也会与waitKey有冲突。 可以考虑不使用opencv的waitKey,键盘操作和控制命令完全由GUI来完成。 写了一个gtk+2.0/opencv的示例(代码不严谨,实际应用中应该避免使用多线程,尽可能用gtk的timeout和idle功能来实现)
[/quote] [/quote]
chehw_1 2015-12-01
  • 打赏
  • 举报
回复
也许是你控制视频输入的代码放置的位置不对(比如放在了GUI的消息或事件响应的代码中),使得GUI界面无法刷新(GUI界面必须等你的代码处理完毕,结束上一事件响应后才能刷新)。
引用 14 楼 karen99 的回复:
谢谢你!你的代码我都收藏了,有时间来慢慢学习,现在碰巧我需要一个图像来做GUI,所以就显示那个图像然后用waiKey()来输入命令了,算是暂时解决了这个问题。 想再请教你一个问题,都是多线程里比较基本的问题,再次感谢你的耐心 根据我以上的思路,会有两个图像显示,一个是视频输入,一个是我的用户界面图像,我运行了程序,发现有时候那个用户界面图像很久都不出现。想要的结果是,两个线程都运行一下下,也就是两个图像都能看见了,然后再进入系统自己调度的状态,不知道需要怎么控制线程产生的时间才能达到这个效果,再次感谢您的帮助 [quote=引用 13 楼 chehw_1 的回复:] 如果使用了其他GUI库,很可能也会与waitKey有冲突。 可以考虑不使用opencv的waitKey,键盘操作和控制命令完全由GUI来完成。 写了一个gtk+2.0/opencv的示例(代码不严谨,实际应用中应该避免使用多线程,尽可能用gtk的timeout和idle功能来实现)
[/quote]
karen99 2015-12-01
  • 打赏
  • 举报
回复
谢谢你!你的代码我都收藏了,有时间来慢慢学习,现在碰巧我需要一个图像来做GUI,所以就显示那个图像然后用waiKey()来输入命令了,算是暂时解决了这个问题。 想再请教你一个问题,都是多线程里比较基本的问题,再次感谢你的耐心 根据我以上的思路,会有两个图像显示,一个是视频输入,一个是我的用户界面图像,我运行了程序,发现有时候那个用户界面图像很久都不出现。想要的结果是,两个线程都运行一下下,也就是两个图像都能看见了,然后再进入系统自己调度的状态,不知道需要怎么控制线程产生的时间才能达到这个效果,再次感谢您的帮助
引用 13 楼 chehw_1 的回复:
如果使用了其他GUI库,很可能也会与waitKey有冲突。 可以考虑不使用opencv的waitKey,键盘操作和控制命令完全由GUI来完成。 写了一个gtk+2.0/opencv的示例(代码不严谨,实际应用中应该避免使用多线程,尽可能用gtk的timeout和idle功能来实现)
chehw_1 2015-12-01
  • 打赏
  • 举报
回复
如果使用了其他GUI库,很可能也会与waitKey有冲突。 可以考虑不使用opencv的waitKey,键盘操作和控制命令完全由GUI来完成。 写了一个gtk+2.0/opencv的示例(代码不严谨,实际应用中应该避免使用多线程,尽可能用gtk的timeout和idle功能来实现)

/*
 * test6.cpp
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <gtk/gtk.h>
#include <time.h>

using namespace cv;
volatile int fExit; //定义一个全局变量,标记是否退出工作线程

typedef struct GUI_PARAM
{
	GtkWidget * window;
	pthread_t display;
	VideoCapture * p_cap;
}GUI_PARAM_t;

GUI_PARAM_t gui;


void * Capture_Display_Thread(void * param)
{
	char *p_data = (char *)param;


	//~ char key_input;
	long exit_code = 0;
	Mat frame;
	VideoCapture cap(0);
	if(!cap.isOpened())  // check if we succeeded
	{
		exit_code = -2;

	}
	cvNamedWindow("Ori", CV_WINDOW_NORMAL);
//	cvSetWindowProperty("Ori", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);


	while(!fExit && *p_data != 'q' && *p_data != 'Q') // 注意此处应用 *p_data
	{
		printf("\n displaying Video\n");

		cap >> frame; // get a new frame from camera
		if((frame.rows > 0) && (frame.cols > 0))
		{
			cv::imshow("Ori", frame);
		}
	  
		//~ key_input=cv::waitKey(30)%256;
	  //~ 
		//~ if(key_input >0)
			//~ printf("key_input = %c(%.2x)\n",key_input, key_input);
		//~ 
		//~ if(key_input =='q' || key_input =='Q')
		//~ {
			//~ *p_data = key_input;
			//~ break;
		//~ }

		
		//~ sleep(1);
	#ifndef _WIN32
		usleep(100000);
	#else
		Sleep(100);
	#endif
		
		
		
	}
	
	*p_data = 'q';
	printf("stopped.\n");
	
	pthread_exit((void *)exit_code);
	
}

static void on_quit(GtkWidget * widget, gpointer data)
{
	void * exit_disp = NULL;
	GtkWidget * window = (GtkWidget * )data;
	fExit = TRUE;
	pthread_join(gui.display, &exit_disp);
	printf("on_quit.\n");
	gtk_widget_destroy(window);
	return;
}

int main(int argc, char * argv[])
{
    char mydata = 0;
    
    //~ void * exit_disp = NULL;
    int rc;

    memset(&mydata, 0, sizeof(char));
    
	GtkWidget * window;
	GtkWidget * button;
	
	gtk_disable_setlocale();
	gtk_init(&argc, &argv);
	
    rc = pthread_create(&display, NULL, Capture_Display_Thread, (void *)&mydata);

	if(0 != rc) return -1;
	
	gui.display = display;	
	
	gui.window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_widget_set_size_request(window, 200, 50);
	
	g_signal_connect_swapped(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
	
	gtk_container_set_border_width(GTK_CONTAINER(window), 10);
	button = gtk_button_new_with_label("quit");
	
	g_signal_connect(button, "clicked", G_CALLBACK(on_quit), window);
	
	gtk_container_add(GTK_CONTAINER(window), button);
	gtk_widget_show_all(window);
	
	gtk_main();



    printf("gui = %c\n", mydata); // 此处应该将'%s'改为'%c'


    return 0;
}
编译: g++ -Wall -o test6 test6.cpp `pkg-config --cflags opencv` `pkg-config --libs opencv` -lpthread `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`
karen99 2015-12-01
  • 打赏
  • 举报
回复
非常感谢你的时间!实在不行,我可不可以在GUI线程也打开一个图像,这样就可以用waitKey接受命令了,同时还可以用这个图像做界面。
引用 11 楼 chehw_1 的回复:
[quote=引用 10 楼 chehw_1 的回复:] 另一种方式(不使用waitKey): 把Capture_Display_Thread中与waitKey相关的代码注释掉,用sleep(1); 替代。然后GUI_Thread中的终止命令就有效了。 上面写错了,测试了一下不行。 请忽略吧
chehw_1 2015-12-01
  • 打赏
  • 举报
回复
引用 10 楼 chehw_1 的回复:
另一种方式(不使用waitKey): 把Capture_Display_Thread中与waitKey相关的代码注释掉,用sleep(1); 替代。然后GUI_Thread中的终止命令就有效了。


void * Capture_Display_Thread(void * param)
{
	char *p_data = (char *)param;


	char key_input;
	long exit_code = 0;
	Mat frame;
	VideoCapture cap(0);
	if(!cap.isOpened())  // check if we succeeded
	{
		exit_code = -2;

	}
	cvNamedWindow("Ori", CV_WINDOW_NORMAL);
//	cvSetWindowProperty("Ori", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);


	while(!fExit && *p_data != 'q' && *p_data != 'Q') // 注意此处应用 *p_data
	{
		printf("\n displaying Video\n");

		cap >> frame; // get a new frame from camera
		if((frame.rows > 0) && (frame.cols > 0))
		{
			cv::imshow("Ori", frame);
		}
	  
		//~ key_input=cv::waitKey(30)%256;
	  //~ 
		//~ if(key_input >0)
			//~ printf("key_input = %c(%.2x)\n",key_input, key_input);
		//~ 
		//~ if(key_input =='q' || key_input =='Q')
		//~ {
			//~ *p_data = key_input;
			//~ break;
		//~ }

		sleep(1);
		
	}
		
	printf("stopped.\n");
	
	pthread_exit((void *)exit_code);
	
}
上面写错了,测试了一下不行。 请忽略吧
chehw_1 2015-12-01
  • 打赏
  • 举报
回复
另一种方式(不使用waitKey): 把Capture_Display_Thread中与waitKey相关的代码注释掉,用sleep(1); 替代。然后GUI_Thread中的终止命令就有效了。


void * Capture_Display_Thread(void * param)
{
	char *p_data = (char *)param;


	char key_input;
	long exit_code = 0;
	Mat frame;
	VideoCapture cap(0);
	if(!cap.isOpened())  // check if we succeeded
	{
		exit_code = -2;

	}
	cvNamedWindow("Ori", CV_WINDOW_NORMAL);
//	cvSetWindowProperty("Ori", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);


	while(!fExit && *p_data != 'q' && *p_data != 'Q') // 注意此处应用 *p_data
	{
		printf("\n displaying Video\n");

		cap >> frame; // get a new frame from camera
		if((frame.rows > 0) && (frame.cols > 0))
		{
			cv::imshow("Ori", frame);
		}
	  
		//~ key_input=cv::waitKey(30)%256;
	  //~ 
		//~ if(key_input >0)
			//~ printf("key_input = %c(%.2x)\n",key_input, key_input);
		//~ 
		//~ if(key_input =='q' || key_input =='Q')
		//~ {
			//~ *p_data = key_input;
			//~ break;
		//~ }

		sleep(1);
		
	}
		
	printf("stopped.\n");
	
	pthread_exit((void *)exit_code);
	
}
chehw_1 2015-12-01
  • 打赏
  • 举报
回复
Windows下对很多标准的实现并不是很好。 Windows下如果编译有问题,可以把pthread_exit(0); 改为 return NULL; 再试一下。
karen99 2015-12-01
  • 打赏
  • 举报
回复
非常感谢你的耐心和你的帮助,我运行了一下你新附的代码,返回值的确是正确的,谢谢你指出opencv输入的问题,不知道waitKey()会不会解决这个问题,我会试一下。 另一个奇怪的问题是,因为我想在windows环境下开发,就装了一个pthread-w32-2-8-0在我的电脑上,问题是以上代码在Linux编译运行得好好的,在Windows下却总是提示 'GUI_Thread' : must return a value 的错误。 再次感谢您的帮助
引用 7 楼 chehw_1 的回复:
稍微修改了一下你的代码,已测试通过。
chehw_1 2015-12-01
  • 打赏
  • 举报
回复
稍微修改了一下你的代码,已测试通过。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
volatile int fExit; //定义一个全局变量,标记是否退出工作线程


void *GUI_Thread(void * param)
{
// 此处应该是一个GUI界面,点击退出按钮时设置 fExit = TRUE;
// 由于opencv的影响,从console里可能无法读取键盘输入

	char *p_data = (char *)param;

	char c;
	printf("please enter a command (q = exit): \n");
	scanf("%[^\n]%*c", &c); //"%[^\n]%*"的作用是丢弃按回车键后多出来的'\n'
	if(c == 'q' || c == 'Q')
	{
		*p_data = c;
	}

	printf("GUI_Thread exited.\n"); // 永远不会执行到此行(因为stdin被opencv重定向了,scanf语句将永远停留了等待输入状态)

	pthread_exit(0);
}

void * Capture_Display_Thread(void * param)
{
	char *p_data = (char *)param;


	char key_input;
	long exit_code = 0;
	Mat frame;
	VideoCapture cap(0);
	if(!cap.isOpened())  // check if we succeeded
	{
		exit_code = -2;

	}
	cvNamedWindow("Ori", CV_WINDOW_NORMAL);
	cvSetWindowProperty("Ori", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);


	while(!fExit && *p_data != 'q' && *p_data != 'Q') // 注意此处应用 *p_data
	{
		printf("\n displaying Video\n");

		cap >> frame; // get a new frame from camera
		if((frame.rows > 0) && (frame.cols > 0))
		{
			cv::imshow("Ori", frame);
		}
	  
		key_input=cv::waitKey(30)%256;
	  
		if(key_input >0)
			printf("key_input = %c(%.2x)\n",key_input, key_input);
		
		if(key_input =='q' || key_input =='Q')
		{
			*p_data = key_input;
			break;
		}

		//sleep(1);
		
	}
		
	printf("stopped.\n");
	
	pthread_exit((void *)exit_code);
	
}

int main(int argc, char * argv[])
{
    char mydata = 0;
    pthread_t display,gui;
    void * exit_disp = NULL;
//    void * exit_gui = NULL;
    memset(&mydata, 0, sizeof(char));
    
    printf("start...\n");
    int rc = pthread_create(&gui, NULL, GUI_Thread, (void *)&mydata);

    rc = pthread_create(&display, NULL, Capture_Display_Thread, (void *)&mydata);

	if(0 != rc) return -1;

    pthread_join(display, &exit_disp);


//	pthread_join(gui, &exit_gui);  // 必须注释掉此行,因为标准输入(stdin)已经被openvc重定向了,GUI_Thread中接收不到键盘输入,会死锁


    printf("gui = %c\n", mydata); // 此处应该将'%s'改为'%c'


    return 0;
}
karen99 2015-12-01
  • 打赏
  • 举报
回复
非常感谢大家的回复和帮助,特别感谢两位附代码的同学,因为我需要理解一下大家的代码,所以回复晚了,对不起。 我根据Chehw_1的代码写了如下的程序,其中有两个线程,一个线程用于显示,一个线程用于检查键盘输入,如果输入是Q或者q,就终止显示线程。 运行后发现尽管在GUI线程输入Q,用printf 看到的永远都是NULL,显示线程也不会被终止。再次请教大家,为什么传递参数会失败呢。我用Chehw_1的源代码看,他的参数传递却是成功的,我哪里做错了呢? 还有一个疑问是 pthread_join明明是用来终止线程的,为什么叫Join,真的是很难理解。 再次感谢大家!
引用 1 楼 bjtea 的回复:
/quote] [quote=引用 2 楼 fxbszj 的回复:]
引用 4 楼 q3733353520 的回复:
引用 5 楼 chehw_1 的回复:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <unistd.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; volatile int fExit; //定义一个全局变量,标记是否退出工作线程 void *GUI_Thread(void * param) { char *p_data = (char *)param; char c; printf("please enter a command (q = exit): \n"); scanf("%[^\n]%*c", &c); //"%[^\n]%*"的作用是丢弃按回车键后多出来的'\n' if(c == 'q' || c == 'Q') { *p_data = c; } pthread_exit(0); } void * Capture_Display_Thread(void * param) { char *p_data = (char *)param; char key_input; long exit_code = 0; Mat frame; VideoCapture cap(0); if(!cap.isOpened()) // check if we succeeded { exit_code = -2; } cvNamedWindow("Ori", CV_WINDOW_NORMAL); cvSetWindowProperty("Ori", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN); while(!fExit && p_data != 'q' && p_data != 'Q') // 检测是否需要退出线程 { printf("\n displaying Video\n"); cap >> frame; // get a new frame from camera if( frame.rows>0&&frame.cols > 0) { cv::imshow("Ori", frame); key_input=cv::waitKey(30)%256; } //printf("key_input = %s",key_input); if(key_input =='q' || key_input =='Q') { break; } sleep(1); } // 根据需要,确定线程的返回值 if(fExit > 0) exit_code = fExit; else exit_code = -1; // 线程退出状态的返回值类型为void *, // 此示例中,返回值为long型,需要强制类型转换,将long转换为void * pthread_exit((void *)exit_code); /* 也可以写成: return ((void *)exit_code); */ } int main(int argc, char * argv[]) { char c; char mydata; pthread_t display,gui; void * exit_disp = NULL; void * exit_gui = NULL; memset(&mydata, 0, sizeof(char)); int rc = pthread_create(&gui, NULL, GUI_Thread, (void *)&mydata); rc = pthread_create(&display, NULL, Capture_Display_Thread, (void *)&mydata); pthread_join(display, &exit_disp); pthread_join(gui, &exit_gui); printf("gui = %s",mydata); // printf("mydata = %d, thread exit code = %d\n", mydata, rc); return 0; }
chehw_1 2015-11-29
  • 打赏
  • 举报
回复


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <stdint.h>
#include <pthread.h>
#include <unistd.h>


typedef int MYDATA_t;
volatile int fExit; //定义一个全局变量,标记是否退出工作线程



void * worker_thread(void * param)
{
	long exit_code = 0;
	MYDATA_t * p_data = (MYDATA_t *)param;
	if(NULL != p_data)
	{
		*p_data = 100;
	}
	
	
	while(!fExit) // 检测是否需要退出线程
	{
		// do sth. 
		sleep(1);
	}
	
	// 根据需要,确定线程的返回值
	if(fExit > 0) exit_code = fExit;
	else exit_code = -1;
	
	// 线程退出状态的返回值类型为void *,
	// 此示例中,返回值为long型,需要强制类型转换,将long转换为void *
	pthread_exit((void *)exit_code);
	/* 也可以写成:
	return ((void *)exit_code);
	*/
}

int main(int argc, char * argv[])
{
//	char ** var;
	char c;
	
	MYDATA_t mydata;
	memset(&mydata, 0, sizeof(MYDATA_t));
	
	pthread_t th;
	
	// 线程退出状态的返回值类型为void *
	void * exit_code = NULL;
	
	// 如果想在pthread_create中传递参数并取得修改后的数值,需要传递指针
	int rc = pthread_create(&th, NULL, worker_thread, (void *)&mydata); 
	
	while(1)
	{
		printf("please enter a command (q = exit): \n");
		scanf("%[^\n]%*c", &c); //"%[^\n]%*"的作用是丢弃按回车键后多出来的'\n'
		if(c == 'q' || c == 'Q') 
		{
			if(c == 'q') fExit = 1; //如果为'q', 则线程返回1
			else fExit = 2; //如果为'Q', 则线程返回2
			break;
		}
		printf("command = %c, continue waiting...\n", c);
	}
	
	
	pthread_join(th, &exit_code);
	
	// 强制类型转换,将void * 转换为long
	rc = (long)(exit_code);
	printf("mydata = %d, thread exit code = %d\n", mydata, rc);
	
	
	return 0;
}
bjtea 2015-11-28
  • 打赏
  • 举报
回复
你没有给出代码,只能猜测你犯了基本错误。 C语言不支持普通参数回传数值,也就是说参数值被修改后不能回传; 为了回传变量的修改值,必须采用指针形参,传进去地址。然后修改指针指向的那个变量的内容,不必进行回传; 两边都知道地址,都直接能够访问变量的内容。
  • 打赏
  • 举报
回复
引用 3 楼 q3733353520 的回复:
The pthread_create() function starts a new thread in the calling process. The new thread starts execution by invoking start_routine(); arg is passed as the sole argument of start_routine(). The new thread terminates in one of the following ways: * It calls pthread_exit(3), specifying an exit status value that is available to another thread in the same process that calls pthread_join(3). * It returns from start_routine(). This is equivalent to calling pthread_exit(3) with the value supplied in the return statement. * It is canceled (see pthread_cancel(3)). * Any of the threads in the process calls exit(3), or the main thread performs a return from main(). This causes the termination of all threads in the process. The attr argument points to a pthread_attr_t structure whose contents are used at thread creation time to determine attributes for the new thread; this structure is initialized using pthread_attr_init(3) and related functions. If attr is NULL, then the thread is created with default attributes. Before returning, a successful call to pthread_create() stores the ID of the new thread in the buffer pointed to by thread; this identifier is used to refer to the thread in subsequent calls to other pthreads functions. The new thread inherits a copy of the creating thread's signal mask (pthread_sigmask(3)). The set of pending signals for the new thread is empty (sigpending(2)). The new thread does not inherit the creating thread's alternate signal stack (sigaltstack(2)). The new thread inherits the calling thread's floating-point environment (fenv(3)). The initial value of the new thread's CPU-time clock is 0 (see pthread_getcpuclockid(3)). Linux-specific details The new thread inherits copies of the calling thread's capability sets (see capabilities(7)) and CPU affinity mask (see sched_setaffinity(2)).
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); EXAMPLE The program below demonstrates the use of pthread_create(), as well as a number of other functions in the pthreads API. In the following run, on a system providing the NPTL threading imple‐ mentation, the stack size defaults to the value given by the "stack size" resource limit: $ ulimit -s 8192 # The stack size limit is 8 MB (0x800000 bytes) $ ./a.out hola salut servus Thread 1: top of stack near 0xb7dd03b8; argv_string=hola Thread 2: top of stack near 0xb75cf3b8; argv_string=salut Thread 3: top of stack near 0xb6dce3b8; argv_string=servus Joined with thread 1; returned value was HOLA Joined with thread 2; returned value was SALUT Joined with thread 3; returned value was SERVUS In the next run, the program explicitly sets a stack size of 1MB (using pthread_attr_setstacksize(3)) for the created threads: $ ./a.out -s 0x100000 hola salut servus Thread 1: top of stack near 0xb7d723b8; argv_string=hola Thread 2: top of stack near 0xb7c713b8; argv_string=salut Thread 3: top of stack near 0xb7b703b8; argv_string=servus Joined with thread 1; returned value was HOLA Joined with thread 2; returned value was SALUT Joined with thread 3; returned value was SERVUS Program source #include <pthread.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <ctype.h> #define handle_error_en(en, msg) \ do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) struct thread_info { /* Used as argument to thread_start() */ pthread_t thread_id; /* ID returned by pthread_create() */ int thread_num; /* Application-defined thread # */ char *argv_string; /* From command-line argument */ }; /* Thread start function: display address near top of our stack, and return upper-cased copy of argv_string */ static void * thread_start(void *arg) { struct thread_info *tinfo = arg; char *uargv, *p; printf("Thread %d: top of stack near %p; argv_string=%s\n", tinfo->thread_num, &p, tinfo->argv_string); uargv = strdup(tinfo->argv_string); if (uargv == NULL) handle_error("strdup"); for (p = uargv; *p != '\0'; p++) *p = toupper(*p); return uargv; } int main(int argc, char *argv[]) { int s, tnum, opt, num_threads; struct thread_info *tinfo; pthread_attr_t attr; int stack_size; void *res; /* The "-s" option specifies a stack size for our threads */ stack_size = -1; while ((opt = getopt(argc, argv, "s:")) != -1) { switch (opt) { case 's': stack_size = strtoul(optarg, NULL, 0); break; default: fprintf(stderr, "Usage: %s [-s stack-size] arg...\n", argv[0]); exit(EXIT_FAILURE); } } num_threads = argc - optind; /* Initialize thread creation attributes */ s = pthread_attr_init(&attr); if (s != 0) handle_error_en(s, "pthread_attr_init"); if (stack_size > 0) { s = pthread_attr_setstacksize(&attr, stack_size); if (s != 0) handle_error_en(s, "pthread_attr_setstacksize"); } /* Allocate memory for pthread_create() arguments */ tinfo = calloc(num_threads, sizeof(struct thread_info)); if (tinfo == NULL) handle_error("calloc"); /* Create one thread for each command-line argument */ for (tnum = 0; tnum < num_threads; tnum++) { tinfo[tnum].thread_num = tnum + 1; tinfo[tnum].argv_string = argv[optind + tnum]; /* The pthread_create() call stores the thread ID into corresponding element of tinfo[] */ s = pthread_create(&tinfo[tnum].thread_id, &attr, &thread_start, &tinfo[tnum]); if (s != 0) handle_error_en(s, "pthread_create"); } /* Destroy the thread attributes object, since it is no longer needed */ s = pthread_attr_destroy(&attr); if (s != 0) handle_error_en(s, "pthread_attr_destroy"); /* Now join with each thread, and display its returned value */ for (tnum = 0; tnum < num_threads; tnum++) { s = pthread_join(tinfo[tnum].thread_id, &res); if (s != 0) handle_error_en(s, "pthread_join"); printf("Joined with thread %d; returned value was %s\n", tinfo[tnum].thread_num, (char *) res); free(res); /* Free memory allocated by thread */ } free(tinfo); exit(EXIT_SUCCESS); }
  • 打赏
  • 举报
回复
The pthread_create() function starts a new thread in the calling process. The new thread starts execution by invoking start_routine(); arg is passed as the sole argument of start_routine(). The new thread terminates in one of the following ways: * It calls pthread_exit(3), specifying an exit status value that is available to another thread in the same process that calls pthread_join(3). * It returns from start_routine(). This is equivalent to calling pthread_exit(3) with the value supplied in the return statement. * It is canceled (see pthread_cancel(3)). * Any of the threads in the process calls exit(3), or the main thread performs a return from main(). This causes the termination of all threads in the process. The attr argument points to a pthread_attr_t structure whose contents are used at thread creation time to determine attributes for the new thread; this structure is initialized using pthread_attr_init(3) and related functions. If attr is NULL, then the thread is created with default attributes. Before returning, a successful call to pthread_create() stores the ID of the new thread in the buffer pointed to by thread; this identifier is used to refer to the thread in subsequent calls to other pthreads functions. The new thread inherits a copy of the creating thread's signal mask (pthread_sigmask(3)). The set of pending signals for the new thread is empty (sigpending(2)). The new thread does not inherit the creating thread's alternate signal stack (sigaltstack(2)). The new thread inherits the calling thread's floating-point environment (fenv(3)). The initial value of the new thread's CPU-time clock is 0 (see pthread_getcpuclockid(3)). Linux-specific details The new thread inherits copies of the calling thread's capability sets (see capabilities(7)) and CPU affinity mask (see sched_setaffinity(2)).
fxbszj 2015-11-28
  • 打赏
  • 举报
回复
pthread_exit(void *retVal)是结束线程了,是可以利用retVal传递的,需要注意的是,retVal不可以指向此线程函数的局部变量

23,110

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧