unix环境高级编程之线程篇(一)

这篇文章先讲一些线程标识和创建,会在下一篇文章中介绍线程同步。

本章介绍线程篇,第一篇先着重讲线程标识,创建,终止以及一些需要注意的东西,后续继续更新线程同步。


一、线程标识
就像每个进程拥有一个自己的进程ID一样,每个线程也拥有自己的一个线程ID。进程ID在整个系统中是唯一的,但是线程ID不同,它只在它所属的进程环境中有效。进程id有个数据类型pid_t来表示,他是个非负整数。线程id则用pthread_t数据类型来表示,但是这个数据类型在移植的时候不能
简单的当成整数来处理,因此需要使用函数来判定两个线程id是否相等;
#include
int pthread_equal(pthread_t tid1,pthread_t tid2);//若相等则返回非0值,否则返回0
线程需要获取自己的id可使用pthread_self()函数获取
#include
pthread_t pthread_self(void);


二、线程创建
新增线程的创建可以调用pthread_create函数创建;
#include
int pthread_create(pthread_t *tid,const pthread_attr_t *attr,void *(*start)(void),void *arg);//成功返回0,失败返回错误编号
当pthread_create成功返回时,tid指向的内存单元被设置为新创建线程的线程id。
attr参数用于定制各种不同的线程属性,可设置为NULL,创建线程时会使用默认的属性。
新创建的线程从start函数的地址开始运行,该函数只有一个无类型的指针参数arg,如果需要向start函数传递多个参数,需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
线程创建后并不能保证哪个线程先运行,可能是新创建的线程,也可能是调用线程。新创建的线程可以访问进程的地址空间,并且继承调用线程
的浮点环境和信号屏蔽字,但是该线程的未决信号集被清除。


例子:

#include 
#include 
	
pthread_t ntid;
	
void printids(const char* src)
{
	pid_t pid;
	pthread_t tid;
		
	pid = getpid();
	tid = pthread_self();
		
	pthread("%s pid:%u, tid:%u (0x%x)\n",src,(unsigned int pid),(unsigned int)tid,(unsigned int)tid);
}
	
void *thr_fn(*arg)
{
	printids("new thread:");
	return (void*)0;
}
	
int main()
{
	int err;
	err = pthread_create(&ntid,NULL,thr_fn,NULL);
	if(0 != err)
		printf("create pthread err:%s\n",strerror(err));
	printids("main thread:");
	sleep(1);
	exit(0);
}

这个例子要说明两个问题:
1、要处理主线程和新线程之间的竞争,所以主线程要用sleep,否则,因主线程和新线程谁先运行的不确定性,新线程可能在运行之前
主线程已经退出了。导致新线程无法运行。
2、新线程获取自己的id要使用pthread_self()函数获取,不能从全局变量ntid得到,因为新线程可能在主线程之前运行,这样直接
获取的ntid是不正确的。
linux下线程id比较合理,但是进程id的获取却并不匹配,这和linux线程的实现有关,linux使用clone系统调用来实现pthread_create,
clone系统调用创建子进程,这个子进程可以共享父进程一定数量的执行环境,而且这个数量可配。


三、线程终止
进程的任意线程调用了exit,_Exit,_exit,那么整个进程就会终止。以此类似,如果信号的默认动作是终止进程,那么将该信号发
送到线程也会终止整个进程。
单个线程有三种方式退出,在不终止整个进程的情况下停止它的控制流
1、线程指示从启动历程中返回,返回值是线程的终止码
2、线程可以被统一进程中的其他线程终止取消
3、线程调用pthread_exit。

#include
void pthread_exit(void *rval_ptr);
rval_ptr是无类型的,进程中的其他线程可以调用pthread_join函数访问获取到这个值
int pthread_join(pthread_t thread,void *rval_ptr);//成功返回0,出错返回错误编号
调用者将一直阻塞,直到指定线程调用pthread_exit,或返回,或被取消。如果线程被取消,rval_ptr值为PTHREAD_CANCELED,线程可以设置为分离状态,如果线程已经设置为分离状态,那么调用pthread_join就会失败,返回EINVAL.
注意pthread_exit调用的返回值所指向的内存在线程终止后要合法的,否则主线程去访问这个指针指向内存会出现非法访问的问题。


例子比较少,会在后续持续更新,希望继续关注!

你可能感兴趣的:(原创,Linux,pthread)