[C++] 纯文本查看 复制代码
#include <QCoreApplication>
#include <QDebug>
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <pthread.h> // 使用pthread_getattr_np()函数需要定义宏_GNU_SOURCE,而且要在pthread.h前定义
#include <stdio.h>
#include <stdlib.h>
#include "unistd.h" // for sleep
#include <errno.h>
using namespace std;
// Qt Creator非常智能,已经不需要在代码中手动添加pthread头文件和库了,就像一个内置线程库。
/// 线程函数
void* thfunc(void *arg)
{
qDebug() << "in thfunc";
return (void*)0;
}
/// 线程函数1
void* thfunc1(void *arg)
{
int *pn = (int*)arg; // 获取参数地址
int n = *pn; // 解引
qDebug() << QString("in thfunc:n=%1").arg(n);
return (void*)0;
}
/// 线程函数2
void* thfunc2(void *arg)
{
char *str;
str = (char*)arg; // 得到传进来的字符串
qDebug() << QString("in thfunc:str=%1").arg(str);
return (void*)0;
}
typedef struct // 定义结构体的类型
{
int n;
char *str;
}MYSTRUCT;
/// 线程函数3
void* thfunc3(void *arg)
{
MYSTRUCT *p = (MYSTRUCT*)arg; // 得到传进来的字符串
qDebug() << QString("in thfunc:n=%1,str=%2").arg(p->n).arg(p->str); // 打印结构体的内容
return (void*)0;
}
int gn = 10; // 定义一个全局变量,将会在主线程和子线程中用到
/// 线程函数4
void* thfunc4(void *arg)
{
gn++; // 递增1
qDebug() << QString("in thfunc:gn=%1").arg(gn); // 打印全局变量gn的值
return (void*)0;
}
/// 线程函数5
void* thfunc5(void *arg)
{
qDebug() << "sub thread is running";
return NULL;
}
/// 输出自定义的错误信息
#define handle_error_en(en,msg) do {errno=en;perror(msg);exit(EXIT_FAILURE);} while (0)
static void* thread_start7(void *arg)
{
int i,s;
pthread_attr_t gattr; // 定义线程属性结构体
s = pthread_getattr_np(pthread_self(),&gattr); // 获取当前线程属性结构值
if(s!=0)
handle_error_en(s,"pthread_getattr_np"); // 打印错误信息
qDebug() << "Thread's detachstate attribute";
s = pthread_attr_getdetachstate(&gattr,&i); // 从属性结构值中获取分离状态的属性
if(s)
handle_error_en(s,"pthread_attr_getdetachstate");
qDebug() << QString("Detach state =%1").arg(
(i == PTHREAD_CREATE_DETACHED)?"PTHREAD_CREATE_DETACHED" :
(i == PTHREAD_CREATE_JOINABLE)?"PTHREAD_CREATE_JOINABLE" :
"???");
pthread_attr_destroy(&gattr);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 创建一个简单的线程,不传参数
pthread_t tidp;
int ret;
ret = pthread_create(&tidp,NULL,thfunc,NULL); // 创建线程
if(ret)
{
qDebug() << QString("pthread_create failed:%1").arg(ret);
return -1;
}
sleep(1); // main线程挂起1秒,为了让子线程有机会去执行
qDebug() << "in main:thread is created";
// 创建一个线程,并传入整数类型的参数
pthread_t tidp1;
int ret1,n1=110;
ret1 = pthread_create(&tidp1,NULL,thfunc1,&n1); // 创建线程并传递n1的地址
if(ret1)
{
qDebug() << QString("pthread_create failed:%1").arg(ret1);
return -1;
}
pthread_join(tidp1,NULL); // 等待子线程结束
qDebug() << "in main:thread is created";
// 创建一个线程,并传递字符串作为参数
pthread_t tidp2;
int ret2;
const char *str2="hello world";
ret2 = pthread_create(&tidp2,NULL,thfunc2,(void*)str2); // 创建线程并传递str2的地址
if(ret2)
{
qDebug() << QString("pthread_create failed:%1").arg(ret2);
return -1;
}
pthread_join(tidp2,NULL); // 等待子线程结束
qDebug() << "in main:thread is created\n";
// 创建一个线程,并传递结构体作为参数
pthread_t tidp3;
int ret3;
MYSTRUCT mystruct3; // 定义结构体
// 初始化结构体
mystruct3.n = 1100;
mystruct3.str = "hello world!";
ret3 = pthread_create(&tidp3,NULL,thfunc3,(void*)&mystruct3); // 创建线程并传递mystruct3结构体的地址
if(ret3)
{
qDebug() << QString("pthread_create failed:%1").arg(ret3);
return -1;
}
pthread_join(tidp3,NULL); // 等待子线程结束
qDebug() << "in main:thread is created\n";
// 创建一个线程,共享进程数据
pthread_t tidp4;
int ret4;
ret4 = pthread_create(&tidp4,NULL,thfunc4,NULL); // 创建线程
if(ret4)
{
qDebug() << QString("pthread_create failed:%1").arg(ret4);
return -1;
}
pthread_join(tidp4,NULL); // 等待子线程结束
gn++; // 子线程结束后,gn再递增1
qDebug() << QString("in main:gn=%1").arg(gn); // 再次打印全局变量gn的值
// 创建一个可分离线程
/* 分离状态(Detached State)是线程很重要的一个属性。POSIX线程的分离状态决定一个线程以什么样的方式来终止自己。
* 这里所说的分离状态是POSIX标准下的属性所特有的,用于表明该线程以何种方式终止自己。默认的分离状态是可连接的,即创建线程时如果使用默认属性,
* 则分离状态属性就是可连接的,因此默认属性下创建的线程是可连接的线程。
* POSIX下的线程要么是分离的,要么是非分离的(也称可连接的,joinable)。前者用宏PTHREAD_CREATE_DETACHED表示,
* 后者用宏PTHREAD_CREATE_JOINABLEB表示。默认情况下创建的线程是可连接的,一个可连接的线程可以被其他线程收回资源和杀死(或称撤销),
* 并且不会主动释放资源(比如堆栈空间),必须等待其他线程来回收它占用的资源,因此我们要在主线程中调用pthread_join()函数(阻塞函数,
* 当它返回时所等待的线程的资源就被释放了)。
* 如果是可连接的线程,那么线程函数自己返回结束时或调用pthread_exit()结束时都不会释放线程所占用的堆栈和线程描述符(总计8KB多),
* 必须调用pthread_join()且返回后才会释放这些资源。这对于父进程长时间运行的进程来说会是灾难性的。
* 因为父进程不退出并且没有调用pthread_join(),则这些可连接线程的资源就一直不会释放,相当于变成僵尸线程,僵尸线程越来越多,
* 再想创建新线程时将没有资源可用!
* 重要的事情再说一遍,一个可连接的线程所占用的内存仅当有线程对其执行pthread_join()后才会释放,因此为了避免内存泄漏,
* 可连接的线程在终止时,要么已被设为DETACHED(可分离),要么调用pthread_join()函数来回收资源。
* 另外,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join()的线程将得到错误代码ESRCH。
* 可分离的线程。这种线程运行结束时,它的资源将会立刻被系统回收。可以这样理解,这种线程是能独立(分离)出去的,可以自生自灭,父线程不用管它。
* 一个线程设置为可分离状态有两种方法:一种方法是调用函数pthread_detach(),它可以将线程转换为可分离线程;
* 另一种方法是在创建线程时就将它设置为可分离状态,基本过程是首先初始化一个线程属性的结构体变量(通过函数pthread_attr_init()),
* 然后将它设置为可分离状态(通过函数pthread_attr_setdetachstate()),最后将该结构体变量的地址作为参数传入线程创建函数 pthread_create(),
* 这样所创建出来的线程就直接处于可分离状态了。
*/
pthread_t thread_id5;
pthread_attr_t thread_attr5;
struct sched_param thread_param5;
size_t stack_size5;
int res5;
res5 = pthread_attr_init(&thread_attr5);
if(res5)
qDebug() << "pthread_attr_init failed:" << res5;
res5 = pthread_attr_setdetachstate(&thread_attr5,PTHREAD_CREATE_DETACHED);
if(res5)
qDebug() << "pthread_attr_setdetachstate failed:" << res5;
res5 = pthread_create(&thread_id5,&thread_attr5,thfunc5,NULL);
if(res5)
qDebug() << "pthread_create failed:" << res5;
qDebug() << "main thread will exit";
sleep(1);
// 创建一个可分离的线程,且main线程先退出
/* 对于可连接的线程,主线程可以调用pthread_join()函数等待子线程结束。
* 对于可分离线程,并没有这样的函数,但是可以先让主线程退出而进程不退出,一直等到子线程退出了才退出进程。
* 也就是说,在主线程中调用函数pthread_exit(),如果在main线程中调用了pthread_exit(),那么此时终止的只是main线程,
* 而进程的资源会为由main线程创建的其他线程保持打开的状态,直到其他线程都终止。
* 值得注意的是,如果在非main线程(其他子线程)中调用pthread_exit(),则不会有这样的效果,只会退出当前子线程。
*/
pthread_t thread_id6;
pthread_attr_t thread_attr6;
struct sched_param thread_param6;
size_t stack_size6;
int res6;
res6 = pthread_attr_init(&thread_attr6); // 初始化线程结构体
if(res6)
qDebug() << "pthread_attr_init failed:" << res6;
res6 = pthread_attr_setdetachstate(&thread_attr6,PTHREAD_CREATE_DETACHED); // 设置分离状态
if(res6)
qDebug() << "pthread_attr_setdetachstate failed:" << res6;
res6 = pthread_create(&thread_id6,&thread_attr6,thfunc5,NULL); // 创建一个可分离的线程
if(res6)
qDebug() << "pthread_create failed:" << res6;
qDebug() << "main thread will exit";
pthread_exit(NULL); // 主线程退出,但进程不会此刻退出,下面的语句不会再执行
qDebug() << "main thread has exited, this line will not run"; // 此句不会执行
/* 正如我们预料的那样,在main线程中调用了函数pthread_exit()后将退出main线程,但进程并不会在此刻退出,而是等到子线程结束后才退出。
* 因为是分离的线程,所以它结束的时候所占用的资源会立刻被系统回收。如果是一个可连接的(joinable)线程,
* 则必须在创建它的线程中调用 pthread_join()函数来等待可连接线程的结束并释放该线程占用的资源。
* 在任何一个时间点上,线程是可连接的(Joinable),或者是分离的(Detached)。一个可连接的线程在自己退出或pthread_exit()时
* 都不会释放线程所占用堆栈和线程描述符(总计8KB多),需要通过其他线程调用pthread_join()之后才释放这些资源;
* 一个分离的线程是不能被其他线程回收或杀死的,所占的资源在它终止时由系统自动释放。
*/
// 获取线程的分离状态属性
pthread_t phr7;
int s7;
s7 = pthread_create(&phr7,NULL,&thread_start7,NULL); // 创建线程
if(s7!=0)
{
handle_error_en(s7,"pthread_create");
return 0;
}
pthread_join(phr7,NULL); // 等待子线程结束
return a.exec();
}