Ubuntu Linux编程快速入门(1-0)-系统API-初识pthread


使用posix thread(即pthread)写的代码,在连接时需要加入选项-pthread(老版本中可能不得不使用-lpthread)。
笔者平时倾向于使用C++,文中的nullptr就是C++11的代码。不习惯或不使用C++11的读者将其改成NULL即可;为了避免麻烦,笔者在下文中一般会使用-std=c++17。于是笔者的编译和连接指令为:

g++ -c target.cpp -o target.o -std=c++17
g++ target.o -pthread

或者直接使用:

g++ target.cpp -o target -std=c++17 -pthread

创建线程

基本使用

/*
需要pthread.h
@brief 启动新线程
@param thread 输出,成功启动线程的情形下,将会获得专用于该posix thread的一个pthread_t值。
@param attr 输入,线程启动时的属性。
@param start_routine 输入,将被作为线程入口。
@param arg 输入,传递给线程的参数。
@return 成功为0,否则非0。
*/
int pthread_create(pthread_t* thread,pthread_attr_t* attr,void* (*start_routine)(void*),void* arg)

本文中暂不考虑attr和arg。于是本文中涉及的形式为:

int pthread_create(pthread_t* thread,nullptr,void* (*start_routine)(void*),nullptr)

如上文所述,pthread_create的作用是启动新线程。很多人将它误解为先创建并挂起一个线程,这种认识是不正确的。此外,很多人认为线程函数必须是static的;但笔者在使用中并未遇到非static入口带来的问题;但作为线程入口的成员函数确实应当声明为static的,因为涉及到this指针。若哪位前辈知道线程入口需要是static这个说法的正误和原因,还请不吝赐教。

样例代码

#include<pthread.h>
#include<unistd.h>
#include<cstdio>
#include<sys/syscall.h>
pthread_t id1,id2,id3;
void* thread1(void* src){
	printf("a\n");
	pthread_exit(nullptr);
	return nullptr;
}
void* thread2(void* src){
	printf("b\n");
	pthread_exit(nullptr);
	return nullptr;
}
void* thread3(void* src){
	printf("c\n");
	pthread_exit(nullptr);
	return nullptr;
}
int main(){
	pthread_create(&id1,nullptr,thread1,nullptr);
	pthread_create(&id2,nullptr,thread2,nullptr);
	pthread_create(&id3,nullptr,thread3,nullptr);
	usleep(1000000);
	return 0;
}

运行结果如下:

c
b
a

可见,pthread_create是会立即启动线程的(尽管出现了线程不安全的现象;可以看出,在笔者的机器上,程序输出顺序和thread被创建的顺序相反。笔者也不太清楚这是为什么,还请赐教。但另一方面,出现这种情况的代码一定是不好的,多线程程序的运行结果不应当过度依赖于启动顺序,除非需要特意这样做。此外,本文中暂不讨论线程安全问题,读者只要知道奇怪的输出顺序是因为线程没有被良好管理即可。)
如果注释掉usleep行,一般不会有任何输出,这是因为主线程创建过其他线程之后直接return退出了。所以务必注意主线程退出会导致进程内其他线程直接被终止

退出线程

基本使用

/*
需要pthread.h
@brief 退出线程并返回一个值
@param retval 用于获取线程返回值的东西
@return 没有返回值
*/
void pthread_exit(void* retval)

本文中暂不讨论返回值,样例代码中仅展示pthread_exit(nullptr)。

样例代码1

#include<pthread.h>
#include<cstdio>
#include<unistd.h>
#include<sys/syscall.h>
#include<sys/types.h>
pthread_t id1,id2;
void* thread1(void* src){
	printf("Thread1 entered\n");
	pthread_exit(nullptr);
	printf("This is not supposed to be shown - thread1\n");
	return nullptr;
}
void* thread2(void* src){
	printf("Thread2 entered\n");
	pthread_exit(nullptr);
	printf("This is not supposed to be shown - thread2\n");
	return nullptr;
}
int main(){
	pthread_create(&id1,nullptr,&thread1,nullptr);
	pthread_create(&id2,nullptr,&thread2,nullptr);
	usleep(1000000);
	return 0;
}

运行结果:

Thread2 entered
Thread1 entered

可以看到,pthread_exit(nullptr)后的语句未被执行,也即pthread_exit(void*)会立即终止线程

样例代码2

#include<pthread.h>
#include<cstdio>
#include<unistd.h>
#include<sys/syscall.h>
#include<sys/types.h>
pthread_t id1,id2;
void* thread1(void* src){
	printf("Thread1 entered\n");
	pthread_exit(nullptr);
	printf("This is not supposed to be shown - thread1\n");
	return nullptr;
}
void* thread2(void* src){
	printf("Thread2 entered\n");
	pthread_exit(nullptr);
	printf("This is not supposed to be shown - thread2\n");
	return nullptr;
}
int main(){
	thread1(nullptr);
	pthread_create(&id1,nullptr,&thread1,nullptr);
	pthread_create(&id2,nullptr,&thread2,nullptr);
	usleep(1000000);
	return 0;
}

运行结果:

Thread1 entered

可见,调用该函数时务必保持高度谨慎,因为pthread_exit(void*)可以结束包括主线程在内的任何当前程序内的线程,包括不是在线程主函数内调用的情形

查看线程描述符和线程tid

基本使用

/*
需要pthread.h
@brief 获取线程描述符
@return 当前线程的描述符
线程描述符在所属进程中唯一,在整个系统下不一定唯一
*/
pthread_t pthread_self()
/*
syscall需要sys/unistd.h,SYS_gettid需要sys/syscall.h
@brief 获取线程tid
@return 线程tid
一般地,线程tid总是唯一
有的资料显示syscall返回int型,但笔者的系统返回的是long int,各位读者请注意根据具体情形进行处理
*/
long int syscall(SYS_gettid)

样例代码

#include<pthread.h>
#include<cstdio>
#include<unistd.h>
#include<sys/syscall.h>
pthread_t id1,id2;
void* thread1(void* src){
	printf("pthread_self()      == %ld\n",pthread_self());
	printf("syscall(SYS_gettid) == %ld\n",syscall(SYS_gettid));
	pthread_exit(nullptr);
	return nullptr;
}
void* thread2(void* src){
	printf("pthread_self()      == %ld\n",pthread_self());
	printf("syscall(SYS_gettid) == %ld\n",syscall(SYS_gettid));
	pthread_exit(nullptr);
	return nullptr;
}
int main(){
	pthread_create(&id1,nullptr,&thread1,nullptr);
	pthread_create(&id2,nullptr,&thread2,nullptr);
	usleep(1000000);
	return 0;
}

运行结果:

pthread_self()      == 140413183706880
syscall(SYS_gettid) == 14691
pthread_self()      == 140413192099584
syscall(SYS_gettid) == 14690

当然,通常而言,每次的运行结果不会相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值