线程是进程内的一个执行分支;线程的执行力度比进程要细。
同一个进程内的多个线程大多数的资源都是共享的,如:代码段、数据段、文件描述符表、每种信号的处理方式、用户id和组id等资源;但是但每个线程各自都有一套独立的寄存器和栈,独立的一组寄存器确保了线程有独立的上下文,能够体现线程是别独立调度的;独立的栈结构确保了运行时执行流不会发生错乱。
线程的优缺点
优点:
相对于进程而言,创建一个新线程的代价要比创建一个新进程小得多;线程之间的切换需要操作系统做的工作要少很多;线程占用的资源要比进程少很多;线程之间(共用一个地址空间)天生就具备共享资源的能力。
I/O密集型应用,为了提高性能,将I/O操作重叠;合理的使用多线程,能提高IO密集型程序的用户体验。(重要用途,如:迅雷的边下边播;平常一边写代码,一边下载库这些都是多线程的用途)
缺点:
健壮性降低:在C、C++程序中当进程中的一个线程崩溃时,会导致其所属进程的所有线程崩溃,也就是说整个进程就会崩溃。(Java程序不会崩)
缺乏访问控制:在一个线程中调用某些OS函数会对整个进程造成影响。
编程难度提高:编写与调试一个多线程程序比单线程程序困难得多。
为什么说线程比进程更加轻量化?
这是一个进程,创建一个进程要创建对应的PCB,对应的页表等一系列工作,创建线程只需要创建对应的PCB,释放同理,所以线程的创建和释放都比进程要更轻轻量化。
根据局部性原理,进程的切换需要的重新加载cache数据,而线程则不需要。
Linux中没有"真正意义上的线程",它只有**轻量级进程(LWP)**的概念,它只会提供轻量级进程的系统调用接口,但是对于用户而言更多关注的数线程的概念,所以我们会使用与原生线程库pthread来对线程操作,现在几乎所有的Linux操作系统都是自带pthread库来操作线程,pthread库集成轻量级系统调用的接口。
Windows的设计是直接将线程的设计在内核当中,而Linux而是采用更加卓越的复用进程的相关数据结构和算法来提供轻量级进程的概念;所以我们使用原生线程库实现的是用户级线程。
Linux中线程使用进程PCB描述实现,并且同一个进程中的所有PCB共用同一个虚拟地址空间,因此相较于传统进程更加的轻量化。使用原生线程库pthread_create创建线程会调用clone轻量级进程接口。pthread_create创建的用户级线程都在共享区进行管理。
接下来使用phtread库创建线程:
说明:下面的代码均为主逻辑代码,查看完整代码并想让程序跑起来请查看gitee项目链接
原型:int pthread_create
(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
功能:创建一个新的线程
参数说明:
thread:输出型参数,返回线程ID
attr:设置线程的属性,attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码
pthread_t pthread_self(void);
功能:获取线程自身id
原型:void pthread_exit(void *retval)
功能:线程终止
参数:
retval:retval注意不要指向一个局部变量。
普通创建的线程可以使用return终止进程,但是main线程return相当于exit函数,会终止整个进程
需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
原型:int pthread_cancel(pthread_t thread)
功能:取消一个执行中的线程
参数:
thread:线程id
返回值:成功返回0;失败返回错误码
代码示例1:
int ret_code = 0;
void* newThread(void*)
{
int count = 0;
while(true)
{
cout << "new thread run ; pid:" << getpid() << endl;
sleep(1);
ret_code = count;
if(++count == 15)
{
pthread_exit(reinterpret_cast<void*>(ret_code));
}
}
}
int main()
{
pthread_t tid;
pthread_create(&tid,nullptr,newThread,nullptr);
int count = 0;
while(true)
{
cout << "main thread run , pid:" << getpid() << endl;
sleep(1);
if(++count == 6)
{
pthread_cancel(tid);
break;
}
}
cout << "new thread exit code number is " << ret_code << endl;
return 0;
}
监控脚本
while :; do ps -aL | head -1 && ps -aL | grep mythead; sleep 1;done
部分输出结果:
main thread run , pid:2853
new thread run ; pid:2853
new thread exit code number is 4
两个执行流,对应的执行流都有相同的pid说明,两个执行流(线程)是在同一个进程中。控制修改count值来控制线程终止还是线程取消。
功能:等待线程结束
原型
int pthread_join(pthread_t thread, void **value_ptr);
参数
thread:线程id
value_ptr:它指向一个指针,后者指向线程的返回值
返回值:成功返回0;失败返回错误码
为什么要线程等待?
//代码实例2:
class Response
{
public:
Response(int result, int exitCode)
: _result(result), _exitCode(exitCode)
{}
public:
int _result;
int _exitCode;
};
class Request
{
public:
Request(int start, int end, string threadName)
: _start(start), _end(end), _threadName(threadName)
{}
public:
int _start;
int _end;
string _threadName;
};
struct Cal
{
//没有static的情况‘void* (Request::*)(void*)’ to ‘void* (*)(void*)’
static void *sum(void *args)
{
Request *req = static_cast<Request *>(args);
Response *resp = new Response(0, 0);
for (int i = req->_start; i <= req->_end; i++)
{
resp->_result += i;
}
delete req;
return resp;
}
};
int main()
{
pthread_t tid;
Request *req = new Request(1, 100, "sumThread");
//注意这里的sum传参
pthread_create(&tid, nullptr, &Cal::sum, req);
int count = 0;
while(1)
{
cout << "main thread " << endl;
sleep(1);
if(count++ == 10)
break;
}
void *ret;
pthread_join(tid, &ret);
Response *resp = static_cast<Response *>(ret);
cout << "ret is " << resp->_result << ",the exitCode is " <<
resp->_exitCode << endl;
return 0;
}
int pthread_detach(pthread_t thread);
返回值:正确返回0,错误返回错误码
//代码示例4
void* sayHi(void* args)
{
//方式2
// pthread_detach(pthread_self());
while(true)
{
cout << "the thread say hi now" << endl;
sleep(1);
if(++count == 5)
break;
}
}
int main()
{
pthread_t tid;
pthread_create(&tid,nullptr,sayHi,nullptr);
// pthread_join(tid,nullptr);//阻塞式等待线程退出,如果不想等呢?线程分离!
// 方式1
pthread_detach(tid);
cout << "the main thread ready exit" << endl;
//joinable和分离是冲突的,一个线程不能既是joinable又是分离的。
// int ret = 0;
// ret = pthread_join(tid,nullptr);
//保证main线程最后退,不然整个进程就会退出
sleep(7);
return 0;
}