线程的创造和生命

线程的创造和生命


在这里插入图片描述

1. 创造新线程

1.1 线程ID

线程进程
pthread_tpid_t
pthread_self()getpid()
pthread_create()fork()

pthread_t:结构体(FreeBSD5.2、Mac OS10.3)/unsigned long int(linux)
/usr/include/bits/pthreadtypes.h
获取线程ID: pthread_self()
一个实例: 获取主线程ID

//获取主线程ID
#include "apue.h"
int main()
{
	pid_t pid;
	pthread_t tid;
	pid = getpid();
	tid = pthread_self();
	printf("pid is %u, tid is %x\n", pid, tid);
	return 0;
}

1.2 创建线程

pthread_create函数:
int pthread_create(pthread_t *restrict tidp,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void *),
void *restrict arg)
第一个参数:新线程的id,如果成功则新线程的id回填充到tidp指向的内存
第二个参数:线程属性(调度策略,继承性,分离性…)
第三个参数:回调函数(新线程要执行的函数)
第四个参数:回调函数的参数
返回值:成功返回0,失败则返回错误码
编译时需要连接库libpthread

1.3 实例:创建线程,打印ID

/*getpid()			获取进程ID
 *pthread_self()	获取县城ID
 *
 *int pthread_create(pthread_t *thread, 
 *					 const pthread_attr_t *attr,
 *					 void *(*start_routine) (void *), 
 *				     void *arg);
 *第一个参数,新线程id,创建成功系统回填
 *第二个参数,新线程到属性,NULL为默认属性
 *第三个参数,新线程到启动函数
 *第四个参数,传递给新线程
 */
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
void print_id(char *s)
{
	pid_t pid;
	pthread_t tid;

	pid = getpid();
	tid = pthread_self();

	printf("%s pid is %u, tid is 0x%x\n", 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);
	return 0;
}

2. 线程的生命周期

2.1 初始线程/主线程

1、当c程序运行时,首先运行main函数。在线程代码中,这个特殊的执行流被称作初始线程或者主线程。你可以在初始线程中做任何普通线程可以做的事情。
2、主线程的特殊性在于,它在main函数返回的时候,会导致进程结束,进程内所有的线程也将会结束。这可不是一个好的现象,你可以在主线程中调用pthread_exit函数,这样进程就会等待所有线程结束时才终止。
3、主线程接受参数的方式是通过argc和argv,而普通的线程只有一个参数void*
4、在绝大多数情况下,主线程在默认堆栈上运行,这个堆栈可以增长到足够的长度。而普通线程的堆栈是受限制的,一旦溢出就会产生错误

2.2 线程的创建

1、主线程是随着进程的创建而创建
2、其他线程可以通过调用函数来创建,主要调用pthread_create
3、请注意,新线程可能在当前线程从函数pthread_create返回之前就已经运行了,甚至新 线程可能在当前线程从函数pthread_create返回之前就已经运行完毕了。

2.3 实例:创造一个线程,主线程打印奇数,新线程打印偶数,交替执行

//DESCRIPTION:	主线程打印奇数,新线程打印偶数,交替执行

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

int flag = 1;

void *thread_fun(void *arg)
{
	int num = 1;
	while(1)
	{
		if(flag==0)
		{
			//将flag置1,这样只有主线程打印一次后,新线程才能打印
			flag=1;
			printf("new thread print num:  %d\n", num*2);
			num++;
		}
		//睡眠,使主线程和新线程交替执行
		sleep(1);
	}
}

int main()
{
	int err, num=0;
	pthread_t tid;

	err = pthread_create(&tid, NULL, thread_fun, NULL);
	if(err != 0)
	{
		printf("create new thread failed \n");
		return 0;
	}
	while(num<20)
	{
		//flag==1主线程打印
		if(flag==1)
		{
			//将flag置0,这样只有新线程打印一次,主线程才能打印
			flag = 0;
			printf("main thread print num: %d\n", num*2+1);
			num++;
		}
		//睡眠,使得主线程和新线程可以交替执行
		sleep(1);
	}
	return 0;
}

2.4 线程的四个基本状态

状态含义
就绪线程能够运行,但是在等待可用的处理器
运行线程正在运行,在多核系统中,可能同时有多个线程在运行
阻塞线程在等待处理器以外的其他条件
终止线程从启动函数中返回,或者调用pthread_exit函数,或者被取消

在这里插入图片描述
回收:
线程的分离属性:

  1. 分离一个正在运行的线程并不影响它,仅仅是通知当前系统该线程结束时,其所属的资源可以回收。一个没有被分离的线程在终止时会保留它的虚拟内存,包括他们的堆栈和其他系统资源,有时这种线程被称为“僵尸线程”。创建线程时默认是非分离的
  2. 如果线程具有分离属性,线程终止时会被立刻回收,回收将释放掉所有在线程终止时未释放的系统资源和进程资源,包括保存线程返回值的内存空间、堆栈、保存寄存器的内存空间等。
  3. 终止被分离的线程会释放所有的系统资源,但是你必须释放由该线程占有的程序资源。由malloc或者mmap分配的内存可以在任何时候由任何线程释放,条件变量、互斥量、信号灯可以由任何线程销毁,只要他们被解锁了或者没有线程等待。但是只有互斥量的主人才能解锁它,所以在线程终止前,你需要解锁互斥量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值