一、线程简介
-
线程是参加体系调度的最小单位。它被包含在进程之中,是进程中的实践运转单位。
-
一个进程中能够创立多个线程,多个线程完成并发运转,每个线程履行不同的使命。
-
每个线程都有其对应的标识,称为线程 ID,线程 ID 运用
pthread_t
数据类型来表明。
二、线程的创立
线程是轻量级的并发履行单元,经过调用Linux体系供给的pthread库中的函数来创立和办理线程。
- 包含头文件:
#include <pthread.h>
- 定义线程函数:
线程函数是线程实践履行的函数,可所以任何能够被调用的函数。线程函数的原型如下:
void* thread_function(void* arg);
其间arg
是传递给线程函数的参数,可所以任何类型的数据。线程函数的回来值为void*
类型,能够回来任何类型的数据。
- 创立线程:
创立线程需求调用pthread_create
函数。该函数的原型如下:
int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);
参数 | 类型 | 描绘 |
---|---|---|
thread |
pthread_t * |
用于存储新线程标识符的指针 |
attr |
const pthread_attr_t * |
用于指定新线程的特点,如栈大小、调度战略等,能够为 NULL,表明运用默许特点 |
start_routine |
void *(*)(void *) |
新线程的开始函数,需求回来 void 指针类型的成果,而且带有一个 void 指针类型的参数 |
arg |
void * |
传递给新线程开始函数的参数,能够为 NULL |
回来值 | int |
0 表明成功,非 0 表明失利,错误代码保存在 errno 中 |
留意:在调用 pthread_create() 函数之后,新线程的履行与调用线程并行进行,它们之间没有特定的履行顺序。
下面是一个创立线程的比如:
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 5; i++) {
printf("这是线程函数,arg=%d, i=%d\n", *(int *)arg, i);
sleep(1);
}
pthread_exit(NULL);
}
int main()
{
pthread_t tid; // 线程标识符
int arg = 123; // 传递给线程函数的参数
// 创立新线程
if (pthread_create(&tid, NULL, thread_func, &arg) != 0) {
printf("线程创立失利!\n");
return 1;
}
// 等待线程完毕并收回资源
if (pthread_join(tid, NULL) != 0) {
printf("线程收回失利!\n");
return 1;
}
printf("线程完毕!\n");
return 0;
}
三、 线程的停止
线程的停止有两种方式:天然停止和强制停止。
线程的天然停止是指线程履行完它的工作后主动退出,而强制停止是指在程序运转过程中,主线程或其他线程显式地停止一个正在运转的线程。
线程天然停止
线程能够经过调用pthread_exit
函数来完成天然停止。pthread_exit
函数的原型如下:
void pthread_exit(void *retval);
pthread_exit
函数 无回来值,其间,参数retval
是线程的退出状况,能够经过pthread_join
函数获取。
下面是一个简略的比如,演示怎么运用pthread_exit
函数停止一个线程:
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 5; i++) {
printf("这是线程函数,i=%d\n", i);
sleep(1);
}
pthread_exit((void *) "线程正常完毕!");
}
int main()
{
pthread_t tid; // 线程标识符
// 创立新线程
if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
printf("线程创立失利!\n");
return 1;
}
// 等待线程完毕并收回资源
void *retval;
if (pthread_join(tid, &retval) != 0) {
printf("线程收回失利!\n");
return 1;
}
printf("%s\n", (char *)retval);
printf("线程完毕!\n");
return 0;
}
上面的示例程序中,咱们在线程函数中调用pthread_exit
函数来停止线程,并回来一个字符串作为退出状况。
在主线程中,咱们运用pthread_join
函数等待线程完毕,并经过指针retval
获取线程的退出状况。
线程强制停止
在Linux中,线程的强制停止能够运用pthread_cancel
函数来完成。pthread_cancel
函数的原型如下:
int pthread_cancel(pthread_t thread);
其间,参数thread
是要撤销的线程标识符。当pthread_cancel
函数被调用时,被撤销的线程将当即退出。
参数 | 类型 | 描绘 |
---|---|---|
thread |
pthread_t |
要撤销的线程标识符 |
回来值 | int |
0 表明成功,非 0 表明失利,错误代码保存在 errno 中 |
留意:调用 pthread_cancel() 函数仅仅向指定线程发送一个撤销恳求,让指定线程尽快退出履行,而不会当即停止它的履行。
线程在接收到撤销恳求后,能够经过调用 pthread_setcancelstate()
和 pthread_setcanceltype()
函数来指定怎么呼应恳求,这里不再展开阐明。
下面是一个简略的比如,演示怎么运用pthread_cancel
函数强制停止一个线程:
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 5; i++) {
printf("这是线程函数,i=%d\n", i);
sleep(1);
}
pthread_exit((void *) "线程正常完毕!");
}
int main()
{
pthread_t tid; // 线程标识符
// 创立新线程
if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
printf("线程创立失利!\n");
return 1;
}
// 等待一段时间后强制停止线程
sleep(2);
if (pthread_cancel(tid) != 0) {
printf("线程撤销失利!\n");
return 1;
}
// 等待线程完毕并收回资源
void *retval;
if (pthread_join(tid, &retval) != 0) {
printf("线程收回失利!\n");
return 1;
}
if (retval == PTHREAD_CANCELED) {
printf("线程被撤销!\n");
} else {
printf("%s\n", (char *)retval);
}
printf("线程完毕!\n");
return 0;
}
上面的示例程序中,主线程调用了pthread_cancel
函数,强制停止了子线程。
在子线程函数中,咱们运用pthread_exit
函数回来了一个字符串,假如子线程正常完毕,那么在主线程中打印出来的将是这个字符串;假如子线程被强制停止,那么在主线程中打印出来的将是线程被撤销!
。
- 不是这个啦
- 我是想说,前面好几次都提到了
线程收回
, 你是不是忘了告知我了 - 不好意思哈,一会儿没忍住就说出来了
四、线程的收回
运用pthread_join
函数等待线程完毕。该函数需求两个参数:线程标识符和指向线程回来值的指针。
int pthread_join(pthread_t thread, void **value_ptr);
参数 | 类型 | 描绘 |
---|---|---|
thread |
pthread_t |
要等待的线程标识符 |
value_ptr |
void ** |
用于获取线程的退出状况的指针,能够为 NULL,表明不关心退出状况 |
回来值 | int |
0 表明成功,非 0 表明失利,错误代码保存在 errno 中 |
留意:调用 pthread_join() 函数会堵塞当前线程,直到指定的线程停止停止。
假如指定的线程现已停止,那么该函数会当即回来,而且不会堵塞。
另外,线程的退出状况只要在 pthread_join() 调用成功时才干被获取,否则 value_ptr 指向的值是未定义的。
假如线程停止后,其它线程没有调用 pthread_join()函数来收回该线程,这个线程会变成僵尸线程,会糟蹋体系资源;若僵尸线程积累过多,那么会导致应
用程序无法创立新的线程。
五、线程的别离
能够运用pthread_detach
函数将线程别离。pthread_detach
函数的原型如下:
int pthread_detach(pthread_t thread);
参数 | 类型 | 描绘 |
---|---|---|
thread | pthread_t | 要别离的线程标识符 |
回来值 | int | 0 表明成功,非 0 表明失利,错误代码保存在 errno 中 |
调用 pthread_detach()
函数将使得指定线程在退出时主动释放其相关资源,而不需求其他线程调用 pthread_join()
函数来等待它的退出并收回资源。
假如指定的线程现已被别离或许现已退出,那么调用 pthread_detach() 函数将回来一个错误。
下面是一个简略的比如,演示怎么运用pthread_detach
函数将线程别离:
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 5; i++) {
printf("这是线程函数,i=%d\n", i);
sleep(1);
}
pthread_exit((void *) "线程正常完毕!");
}
int main()
{
pthread_t tid; // 线程标识符
// 创立新线程
if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
printf("线程创立失利!\n");
return 1;
}
// 别离线程
if (pthread_detach(tid) != 0) {
printf("线程别离失利!\n");
return 1;
}
printf("线程现已别离,将主动收回资源!\n");
// 程序完毕
return 0;
}
上面的示例程序中,咱们在创立线程之后当行将线程别离,并打印一条提示信息,告知用户线程现已别离,将在退出时主动收回资源。
当运转上面的程序时,能够看到如下输出:
线程现已别离,将主动收回资源!
这是线程函数,i=0
这是线程函数,i=1
这是线程函数,i=2
这是线程函数,i=3
这是线程函数,i=4
能够看到,程序创立了一个新线程,并当行将它别离。在子线程中,咱们打印了5个字符串,每个字符串间隔1秒。
在主线程中,咱们打印了一条提示信息,告知用户线程现已别离,将在退出时主动收回资源。最后,程序正常完毕,没有调用pthread_join
函数。
小结
咱们现已介绍了Linux线程的创立、停止、收回、别离等基本操作。
在实践编程中,咱们或许还需求运用一些其他的函数和技巧,例如互斥锁、条件变量、信号量、读写锁等
欲知后事怎么,请听下回分解!
欢迎各位 点赞 ⭐收藏 谈论,如有错误请留言纠正,非常感谢!
以上,假如觉得对你有协助,点个赞再走吧,这样@知微之见也有更新下去的动力!
也欢迎私信我,一同交流!