本文主要介绍Linux多线程编程的快速入门,其中涉及到线程的基础知识、线程识别、线程创建、线程终止、线程终止等相关内容。边肖认为这很好。我就分享到这里,有需要的朋友可以参考一下。
目录
5.1线程连接5.2线程分离本文主要对Linux下的多线程进行介绍。虽然是介绍,但是很详细。希望你能通过这篇文章对Linux多线程编程的概念有一定的了解。如下。
1 线程基本知识
进程是资源管理的基本单位,而线程是系统调度的基本单位。线程是操作系统可以执行调度操作的最小单位。它包含在流程中,是流程中的实际操作单元。线程是指流程中控制流的单个序列。多个线程可以在一个进程中并发,每个线程并行执行不同的任务。
一个进程在某一时刻只能做一件事。有了多个控制线程,程序被设计成在某个时间做多件事,每个线程处理自己的任务。
需要注意的是,即使程序运行在单核处理器上,也能获得多线程编程模式的好处。处理器数量不影响程序结构,所以不管处理器数量多少,程序都可以通过线程来简化。
Linux操作系统使用POSIX线程作为系统标准线程,为操作线程定义了一套API。
2. 线程标识
就像一个进程有一个ID一样,每个线程都有一个线程ID。不同的是,进程ID在整个系统中是唯一的,而线程是依附于进程的,它的线程ID只有在它所属的进程中才有意义。线程ID由pthread _ t表示。
//pthread_self直接返回调用线程的ID
包含pthread.h
pthread _ t pthread _ self(void);
判断两个线程id的大小没有任何意义,但有时可能需要判断两个给定的线程id是否相等。使用以下界面:
//pthread_equal如果t1和t2指定的线程ID相同,返回0;否则,将返回一个非零值。
包含pthread.h
int pthread_equal(pthread_t t1,pthread _ t T2);
3. 线程创建
线程的生命周期从它被创建的那一刻开始。创建线程的接口:
#include pthread.h
int pthread _ create(pthread _ t * thread,const pthread_attr_t *attr,
void *(*start_routine) (void *),void * arg);
功能参数:
Thread (output参数),线程创建成功后pthread_create返回的线程句柄,用于在后续操作线程的API中标记新创建的线程;
Start_routine(输入参数),创建新线程的入口函数;
Arg(输入参数),传递给新线程入口函数的参数;
Attr(输入参数),指定新创建线程的属性,如线程栈大小等。如果值为NULL,则使用系统默认属性。
函数返回值:
成功,返回0;
失败,返回相关错误代码。
注意:
1.主线程,它是一个进程的初始线程,它的入口函数就是主函数。
2.新线程的运行时间。一个线程在被创建后可能不会立即被执行,甚至在创建它的线程结束后还没有被执行;也有可能在当前线程从pthread_create返回之前,新线程已经在运行了,甚至在pthread_create之前,新线程在从当前线程返回之前就已经完成了。
程序示例:
#包含stdio.h
#包含stdlib.h
#include pthread.h
#包括unistd.h
void print id(const char * s){
pid _ t pid
pthread _ t tid
PID=getpid();
tid=pthread _ self();
printf(%s,pid %lu tid %lu (0x%lx)n ,s,(无符号长整型)pid,(无符号长整型)tid,
(无符号长整型)tid);
}
void *thread_func(void *arg){
print ids( new thread:);
return((void *)0);
}
int main() {
int err
pthread _ t tid
err=pthread_create(tid,NULL,thread_func,NULL);
如果(呃!=0) {
fprintf(stderr,创建线程失败。 n’);
退出(-1);
}
printids(“主线程:”);
睡眠(1);
返回0;
}
注意,在上面的程序中,主线程休眠了一秒钟。如果没有,主线程将不会休眠,它可能会退出,这样新线程可能不会运行。我自己注释掉了sleep函数,在新线程可以输出之前发现了很多次。
编译命令:
gcc -o螺纹thread . c-LP螺纹
运行结果如下:
主线程:PID 889 tid 139846854309696(0x7f 30 a 212 f 740)
新线程:PID 889 tid 139846845961984(0x7f 30 a 1939700)
您可以看到两个线程的进程id是相同的。在其流程中共享资源。
4. 线程终止
线程终止有两种形式:被动终止和主动终止。
被动终止有两种方式:
1.当线程所在的进程终止时,任何执行exit、_Exit或_exit函数的线程都会导致该进程终止,从而导致所有附属于该进程的线程终止。
2.其他线程调用pthread_cancel请求取消该线程。
主动终止也有两种方式:
1.在线程的入口函数中执行return语句,主函数(主线程入口函数)执行return语句会导致进程终止,从而导致所有附着在进程上的线程终止。
2.线程调用pthread_exit函数,主函数(主线程入口函数)调用pthread_exit函数。主线程终止,但如果进程中有其他线程,进程将继续存在,进程中的其他线程将继续运行。
线程终止功能:
包含pthread.h
void pthread _ exit(void * retval);
调用线程的pthread_exit函数会导致调用线程终止并返回retval指定的内容。
注意:retval不能指向这个线程的堆栈空间,否则可能会变成一个野指针!
5. 管理线程的终止
5.1 线程的连接一个线程的终止是另一个线程的异步事件。有时,我们希望在执行某些操作之前,等待ID为的线程终止。pthread_join函数为我们提供了这个函数,叫做线程连接:
包含pthread.h
int pthread _ join(pthread _ t thread,void * * retval);
参数描述:
Thread(输入参数),指定我们要等待的线程。
Retval(输出参数),我们等待线程终止时的返回值,是线程入口函数或者调用pthread_exit函数的参数中的返回值。
返回值:
如果成功,则返回0。
错误,返回一个肯定的错误代码。
当线程X与线程Y连接时,如果线程Y还在运行,线程X会阻塞,直到线程Y终止;如果线程Y在被连接之前已经被终止,那么线程X的连接调用将立即返回。
连接线程实际上还有另一层含义。一个线程终止后,如果没有人连接,终止线程占用的资源不会被系统回收,终止线程就会变成僵尸线程。因此,当我们连接到一个线程时,我们实际上是在告诉系统,被终止线程的资源是可以回收的。
注意:再次连接一个已经连接的线程会导致不可预知的行为!
5.2 线程的分离有时候我们并不关心一个线程是否已经被终止,我们只是希望如果一个线程被终止,系统能够自动回收被终止线程占用的资源。pthread_detach函数为我们提供了这个函数,叫做线程分离:
#include pthread.h
int pthread _ detach(pthread _ t thread);
默认情况下,线程被终止,在系统可以恢复其资源之前,需要连接它。如果我们调用pthread_detach函数来分离一个线程,系统会在线程终止后自动回收它的资源。
/*
*文件名:thread_sample1.c
*描述:演示线程的基本操作
*/
#包含stdio.h
#包含stdlib.h
#包括unistd.h
#include pthread.h
/*子线程1的入口函数*/
void *thread_routine1
{
fprintf(stdout, thread1: hello world! n’);
睡眠(1);
/*子线程1在此退出*/
返回NULL
}
/*子线程2入口函数*/
void *thread_routine2
{
fprintf(stdout, thread2:我正在运行. n’);
pthread _ t main _ thread=(pthread _ t)arg;
/*把自己分开,就再也联系不上了*/
pthread _ detach(pthread _ self());
/*确定主线程ID是否等于子线程2ID */
如果(!pthread_equal(main_thread,pthread _ self()){
fprintf(标准输出,线程2:主线程身份证明(identification)不等于线程2 n’);
}
/*等待主线程终止*/
pthread_join(main_thread,NULL);
fprintf(标准输出,线程2:主线程退出! n’);
fprintf(stdout, thread2: exit! n’);
fprintf(标准输出,线程2:进程退出! n’);
/*子线程2在此终止,进程退出*/
pthread_exit(空);
}
int main(int argc,char *argv[])
{
/*创建子线程1*/
pthread _ t t1
if (pthread_create(t1,NULL,thread_routine1,NULL)!=0) {
fprintf(stderr,创建线程失败. n );
退出(-1);
}
/*等待子线程一终止*/
pthread_join(t1,NULL);
fprintf(标准输出,主线程:线程1终止! n n’);
/*创建子线程2,并将主线程身份证明传递给子线程2*/
pthread _ t t2
if (pthread_create(t2,NULL,thread_routine2,(void *)pthread_self())!=0) {
fprintf(stderr,创建线程失败. n );
退出(-1);
}
fprintf(标准输出,主线程:休眠. n’);
睡眠(3);
/*主线程使用pthread_exit函数终止,进程继续存在*/
fprintf(标准输出,主线程:退出! n’);
pthread_exit(空);
fprintf(标准输出,主线程:永远不要到达这里! n’);
返回0;
}
最终的执行结果如下:
线程1:你好,世界!
主线程:线程1终止!
主线:睡觉.
线程2:我正在运行.
线程2:主线程身份证明(identification)不等于线程2
主线程:退出!
线程2:主线程退出!
线程2:退出!
线程2:进程退出!
总结
以上就是本文关于Linux操作系统操作系统多线程编程快速入门的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!