Linux---多线程编程(一)---线程的创建和它的生命周期


前言

本文主要介绍了Linux系统下,多线程开发的基础函数,包括
1.线程的创建
2.线程号的获取

同时讲解了一些多线程的相关概念
1.线程的生命周期
2.线程的分离属性
3.主线程的特殊性

同时中间讲解时有一定的验证代码供参考


一、线程的建立

线程ID进程ID
类型pthread_tpid_t
获取pthread_slef()getpid()
创建pthread_create()fork()

pthread_t类型 :
1.在FreeBSD5.2和Mac OS10.3下面是结构体
2.在linux下面是unsigned ling int(8 Byte),可以在pthreadtypes.h这个头文件中查看,该头文件的路径是“/usr/include/bits/pthreadtypes.h”
可以用命令

		vim      /usr/incldue/bits/pthreadtypes.h

1.线程ID的获取

pthread_self()

头文件:#include<pthread.h>
结构:pthread_t pthread_self(void);
功能:获取当前线程的ID

Eg:获取一个进程的ID和主线程的ID

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>

//编译程序需要用链接库
//gcc -lpthread xxx.c -o xxx
//xxx.c是编写的C语言源文件名
//xxx是你想要生成的可执行文件名

int main()
{
	pid_t pid;
	pthread_t tid;
	pid=getpid();
	tid=pthread_self();
	
	printf(“pid is %u,tid is 0X%x”,pid,tid);
	return 0;
}

2.线程的创建

pthread_create()

头文件:#include<pthread.h>
功能:创建一个线程
结构:int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr,void *(*start_routine)(void *),void *restrict arg);

1.第一个参数:新线程的ID,如果成功则新线程的ID自动回填充到tidp指向的内存,通俗来讲,就是只需要给函数传递一个pthread_t的存储空间,然后函数成功创建新线程后会自动将新线程的ID写到传入的那个存储空间中。
2.第二个参数:线程属性(调度策略,继承性,分离性…),如果用NULL,那就是默认属性。
3.第三个参数:回调函数(就是新线程要执行的事件和内容)
4.第四个参数:回调函数的参数,可以是结构体指针
5. 返回值:成功返回0,失败返回错误码
(错误码的查看可以用命令 vim /usr/include/asm-generic/errno.h 去查看)
在Linux系统下,可以用命令:

	vim    /usr/include/asm-generic/errno.h

Eg:创建线程并且打印线程ID

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


//编译程序需要用链接库
//gcc -lpthread xxx.c -o xxx
//xxx.c是编写的C语言源文件名
//xxx是你想要生成的可执行文件名

void print_id(char *s)
{
	pid_t pid;
	pthread_t tid;
	pid=getpid();
	tid=pthread_self();

	prntf(%s pid is %u,tid is 0x%d”,s,pid,tid);
}

void *thread_fun(void *arg)
{
	print_id(arg);
	return (void*)0;
}



int main()
{
	pthread_t ntid;
	int err;
	err=pthread_create(&ntid,NULL,thread_fun,”new thread”);
	if(err!=0)
	{
		printf(“create new thread failed!\n”);
		return 0;
	}
	print_id(“main thread:);
	sleep(2);//这里的睡眠2s是为了让新线程有机会执行,如果不加这个,还没有来得及执行新线程,主进程就return,结束了。
	return 0;
}

二、线程的生命周期

1.主线程与普通线程

1.当C程序运行时,首先运行main函数。在线程代码中,这个特殊的执行流程称作初始线程或者主线程。

2.主线程区别于其它线程的特殊性在于,它在main函数return的时候,会导致进程结束,也就是进程内的所有线程也将会结束。但是我们可以在主线程调用pthread_exit函数,这样进程就会等到所有线程结束才终止。

3.主线程接收参数是通过argv和argc,而普通线程只有一个参数arg

4.在大多数情况下,主线程在默认堆栈上运行,这个堆栈可以增长到足够的长度,而普通线程的堆栈受到限制,一旦溢出就会出现错误。

5.主线与新线程的运行先后顺序是未知的。

Eg:测试主线程的特殊性

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



//编译程序需要用链接库
//gcc -lpthread xxx.c -o xxx
//xxx.c是编写的C语言源文件名
//xxx是你想要生成的可执行文件名

Struct student{
	Int age;
	Char name[20];
};

void *thread_fun(void *stu)
{
	Printf(“student age is %d,name is %s\n”,((struct student*)stu)->age,((struct student*)stu)->name);//这里需要强制转换,因为stu是void *,需要将它转换为struct student* 才能访问结构的成员。
	return (void*)0;
}



int main(int argc,char *argv[])
{
	pthread_t ntid;
	int err;
	int i;
	int *rval;

	struct student stu;
	stu.age=20;
	memcpy(stu.name,”zhangsan”,20);//复制字符串
	err=pthread_create(&ntid,NULL,thread_fun,(void*)(&stu));
	if(err!=0)
	{
		printf(“create new thread failed!\n”);
		return 0;
	}
	printf(“main thread has %d args”,argc);
	for(i=0;i<argc;i++)
	{
		Printf(“main thread arg is %s\n”,argv[i]);
	}

	pthread_exit(rval);
	return 0;
}

2.线程的生命周期

1.就绪:线程能够运行,但是在等待可用的处理器。当线程被创建的时候,它就处于就绪态,或者当线程解除阻塞也会处于就绪态,就绪态就是等待一个处理器来运行,当一个线程被抢占之后,它立刻又回到就绪态。

2.运行:线程正在运行,在多核系统中,肯同时有多个线程正在运行。当处理器选中一个线程执行时,他立刻变成运行状态.

3.阻塞:线程等待处理器以外的其它条件。线程会在以下情况发生阻塞:试图枷锁一个已经锁住的互斥量,等待某个条件变量,调用singwait等待尚未发生的信号,执行无法完成的IO信号,由于内存页错误。

4.终止:线程从启动函数中返回,或者调用pthread_exit函数,或者被取消。线程通常通过启动函数中返回来终止自己,或者调用pthread_exit退出,或者取消线程。

3.线程的回收与分离属性

分离一个正在运行的线程并不影响它,仅仅是通知当前系统该线程结束时,其所属的资源可以回收。一个没有被分离的线程在终止时会保留它的虚拟内存,包括它的堆栈和其它的系统资源,有时这种线程被称作僵尸线程,创建线程时,默认是非分离的。

如果线程具有分离属性,线程终止时会立刻回收,回收将释放掉所有在线程终止时未释放的系统资源和进程资源,包括保存线程返回值的内存空间,堆栈,保存寄存器的空间等。

终止被分离的线程会释放所有的系统资源,前提是要在该线程占用这些资源的时候释放。由malloc和mmap分配的内存可以在任何时候由任意线程释放,条件变量,互斥量,信号灯可以由任何线程释放,前提是只要它们被解锁了或者没有线程等待。但是只有互斥量的主人才可以解锁,所以线程终止前,要解锁互斥量。


总结

本篇是Linux多线程开发基础篇的第一部分,之后会有更多的内容。
讲解不清晰错误的地方请大家包容指正。
下一篇: Linux—多线程编程(二)—多线程的控制
上一篇: 多线程与多进程(概念详细讲解)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SigmaBull

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值