Linux应用编程—4.pthread_create函数
之前学习了进程有关的东西,现在学习如何创建一个线程。
4.1 pthread_create()函数详情
线程创建函数是:pthread_create()。在Linux终端下,输入man pthread_create,查看函数定义以及使用方法。
NAME
pthread_create - create a new thread
SYNOPSIS
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Compile and link with -pthread.
简单来看,pthread_create是用来创建一个线程,使用时需要包含头文件:pthread.h。函数返回值是int型,有4个入参。特别注意编译时,要加上-pthread。
The pthread_create() function starts a new thread in the calling process. The new thread starts execution by invoking start_routine(); arg is passed as the sole argu‐
ment of start_routine().
pthread_create()函数在调用进程内开始一个新的线程。这个新的线程开始执行是通过调用start_routine()函数。arg作为start_routine()的唯一参数传递。
The attr argument points to a pthread_attr_t structure whose contents are used at thread creation time to determine attributes for the new thread; this structure is ini‐
tialized using pthread_attr_init(3) and related functions. If attr is NULL, then the thread is created with default attributes.
Before returning, a successful call to pthread_create() stores the ID of the new thread in the buffer pointed to by thread; this identifier is used to refer to the
thread in subsequent calls to other pthreads functions.
pthread_create()有4个入参,分别是:pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg。在函数return前,pthread_create()成功调用,新的线程保存它的id号到指针指向的缓存也就是thread,所以,第一个参数传入一个pthread_t类型的地址,用来保存新的线程的id。这个id后面创建其它线程时起作用。attr参数指向pthread_attr_t类型的结构体指针,其内容是线程创建时用于确定新线程的属性。如果attr 时null的话,这个线程创建时是默认属性。void *(*start_routine) (void *)是一个函数指针,是新线程执行的函数入口,arg作为start_routine()的唯一参数传递,如果不需要传递参数,赋值NULL即可。
ETURN VALUE
On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.
有关返回值,当pthread_create()创建函数成功时,返回0。
以上就是关于pthread_create()函数的用法。
4.2 pthread_create()函数编程实践
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
void * thread_function(void *arg);
int main(void)
{
int ret = 0;
pthread_t thread;
ret = pthread_create(&thread, NULL, thread_function, NULL);
if(0 != ret)
{
perror("thread create.");
exit(1);
}
return 0;
}
void * thread_function(void *arg)
{
printf("Thread start running.\n");
while(1)
{
printf("Hello world!\n");
sleep(1);
}
return NULL;
}
假如这个程序按照我们设想的方式执行,如果线程创建成功,则打印:Thread start running.Hello world每隔一秒钟打印一次。如果线程创建失败,则打印thread create.。但是,事实上运行结果是下图这样的:
没有任何现象!这是因为线程是从属于进程的。在线程创建结束后,main函数也执行到了return 0处,main函数就是调用进程,它结束后,系统资源被操作系统回收,线程也随之被回收。所以,运行没有结果。
那么解决方法可以是,在线程没有执行结束后,进程要保持活跃的运行态。我们先简单粗暴的修改下代码。在main函数返回return 0之前,用while(1)将其阻塞。
此时,我们发现线程开始运行,每隔1秒打印一条语句。这里我们让进程保持运行状态,从而新建的线程也开始运行。但是,某些情况下,线程运行结束后,进程因为被while(1)阻塞,得不到释放。如何解决这个问题呢,在此,引入一个新的函数。
4.3 pthread_join()函数详情
在终端输入man pthread_join,查阅该函数定义以及使用方法。
NAME
pthread_join - join with a terminated thread
SYNOPSIS
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
Compile and link with -pthread.
pthread_join函数,返回值是int类型,函数调用成功时,返回值为0。入参有两个pthread_t thread, void **retval。
The pthread_join() function waits for the thread specified by thread to terminate. If that thread has already terminated, then pthread_join() returns immediately. The
thread specified by thread must be joinable.
If retval is not NULL, then pthread_join() copies the exit status of the target thread (i.e., the value that the target thread supplied to pthread_exit(3)) into the lo‐
cation pointed to by retval. If the target thread was canceled, then PTHREAD_CANCELED is placed in the location pointed to by retval.
pthread_join()函数用来等待线程结束,如果那个线程已经结束,该函数会立即返回。如果retval不为空指针,函数会将退出状态保存到retval里面。
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
void * thread_function(void *arg);
int main(void)
{
int ret = 0;
pthread_t thread;
ret = pthread_create(&thread, NULL, thread_function, NULL);
if(0 != ret)
{
perror("thread create.");
exit(1);
}
pthread_join(thread, NULL);
return 0;
}
void * thread_function(void *arg)
{
int i = 0;
printf("Thread start running.\n");
for(i = 0; i < 5; i++)
{
printf("Hello world!\n");
sleep(1);
}
return NULL;
}
该代码利用pthread_join(thread, NULL)监测线程结束,然后返回。也就是只有线程结束,才停止阻塞进程,让进程保持运行。
运行结果:
当线程中的打印语句每隔1秒打印1次,一共打印了5次后,线程结束,随之,进程也结束。pthread_join(thread, NULL)起到了作用。
4.4 进阶
pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);arg作为start_routine()的唯一参数传递,那尝试用arg参数向进程传递参数。比如,传递线程中打印语句的打印次数。
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
void * thread_function(void *arg);
int main(void)
{
int ret = 0;
pthread_t thread;
int count = 7;
ret = pthread_create(&thread, NULL, thread_function, &count);
if(0 != ret)
{
perror("thread create.");
exit(1);
}
pthread_join(thread, NULL);
return 0;
}
void * thread_function(void *arg)
{
int i = 0;
printf("Thread start running.\n");
for(i = 0; i < *((int *)arg); i++)
{
printf("Hello world!\n");
sleep(1);
}
return NULL;
}
运行结果:
我们定义了int型变量count,然后在pthread_create(&thread, NULL, thread_function, &count);中将其地址传入,在线程函数内,这个值被取出,并参与了循环终止条件的判断。根据结果来看,运行是正确的。
4.4 总结
线程创建函数:pthread_create,以及它的入参的含义。线程是从属于进程的,进程结束线程也随之结束。阻塞式等待线程结束可以调用pthread_join()函数。