Linux系统编程 -- 线程的原语

本文尽可能少的文字性的描述以及概念的介绍,直接深入函数的使用。先介绍各个函数的使用,以及细节,最后再将所有的函数整合到一个代码示例中,以充分说明各个函数的特性。
先铺垫几个常用的线程原语函数,通过 man 命令可以查到这些函数以及具体的使用方法。

root@ubuntu:/home# man -k pthread
pthread_attr_destroy (3) - initialize and destroy thread attributes object
pthread_attr_getaffinity_np (3) - set/get CPU affinity attribute in thread attributes object
pthread_attr_getdetachstate (3) - set/get detach state attribute in thread attributes object
pthread_attr_getguardsize (3) - set/get guard size attribute in thread attributes object
pthread_attr_getinheritsched (3) - set/get inherit-scheduler attribute in thread attributes object
pthread_attr_getschedparam (3) - set/get scheduling parameter attributes in thread attributes object
pthread_attr_getschedpolicy (3) - set/get scheduling policy attribute in thread attributes object
pthread_attr_getscope (3) - set/get contention scope attribute in thread attributes object
pthread_attr_getstack (3) - set/get stack attributes in thread attributes object
pthread_attr_getstackaddr (3) - set/get stack address attribute in thread attributes object
pthread_attr_getstacksize (3) - set/get stack size attribute in thread attributes object
pthread_attr_init (3) - initialize and destroy thread attributes object
pthread_attr_setaffinity_np (3) - set/get CPU affinity attribute in thread attributes object
pthread_attr_setdetachstate (3) - set/get detach state attribute in thread attributes object
pthread_attr_setguardsize (3) - set/get guard size attribute in thread attributes object
pthread_attr_setinheritsched (3) - set/get inherit-scheduler attribute in thread attributes object
pthread_attr_setschedparam (3) - set/get scheduling parameter attributes in thread attributes object
pthread_attr_setschedpolicy (3) - set/get scheduling policy attribute in thread attributes object
pthread_attr_setscope (3) - set/get contention scope attribute in thread attributes object
pthread_attr_setstack (3) - set/get stack attributes in thread attributes object
pthread_attr_setstackaddr (3) - set/get stack address attribute in thread attributes object
pthread_attr_setstacksize (3) - set/get stack size attribute in thread attributes object
pthread_cancel (3)   - send a cancellation request to a thread
...

创建线程与退出线程

pthread_create

作用

创建线程

通过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.

DESCRIPTION
       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 argument
       of start_routine().

       The new thread terminates in one of the following ways:

       * It calls pthread_exit(3), specifying an exit status value that is available to another thread in the same process that calls pthread_join(3).

       * It returns from start_routine().  This is equivalent to calling pthread_exit(3) with the value supplied in the return statement.

       * It is canceled (see pthread_cancel(3)).

       * Any of the threads in the process calls exit(3), or the main thread performs a return from main().  This causes the termination of all threads in the process.

       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.

       The new thread inherits a copy of the creating thread's signal mask (pthread_sigmask(3)).  The set of pending signals for the new thread is  empty  (sigpending(2)).   The
       new thread does not inherit the creating thread's alternate signal stack (sigaltstack(2)).

       The new thread inherits the calling thread's floating-point environment (fenv(3)).

       The initial value of the new thread's CPU-time clock is 0 (see pthread_getcpuclockid(3)).

   Linux-specific details
       The new thread inherits copies of the calling thread's capability sets (see capabilities(7)) and CPU affinity mask (see sched_setaffinity(2)).

RETURN VALUE
       On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.

  • 头文件
    #include <pthread.h>
  • 函数原型
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    void *(*start_routine) (void *), void *arg);
  • 参数说明
    • pthread_t *thread:传递一个pthread_t变量地址进来,用于保存新线程的tid(线程ID)
    • const pthread_attr_t *attr:线程属性设置,如使用默认属性,则传NULL
    • void *(*start_routine) (void *):函数指针,指向新线程应该加载执行的函数模块
    • void *arg:指定线程将要加载调用的那个函数的参数
  • 返回值:
    成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其它函数接口而提供的,pthread库本身并不使用它,通过返回值返回错误码更加清晰。
  • 其他说明
    Compile and link with -lpthread.
    typedef unsigned long int pthread_t;

pthread_exit

作用

  • 调用线程退出函数,注意和exit函数的区别,任何线程里exit导致进程退出,其他线程未工作结束,主控线程退出时不能return或exit。
  • 需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
NAME
       pthread_exit - terminate calling thread

SYNOPSIS
       #include <pthread.h>

       void pthread_exit(void *retval);

       Compile and link with -pthread.

DESCRIPTION
       The  pthread_exit()  function  terminates  the  calling  thread and returns a value via retval that (if the thread is joinable) is available to another thread in the same
       process that calls pthread_join(3).

       Any clean-up handlers established by pthread_cleanup_push(3) that have not yet been popped, are popped (in the reverse of the order in which they were  pushed)  and  exe‐
       cuted.  If the thread has any thread-specific data, then, after the clean-up handlers have been executed, the corresponding destructor functions are called, in an unspec‐
       ified order.

       When a thread terminates, process-shared resources (e.g., mutexes, condition variables, semaphores, and file descriptors) are not released, and functions registered using
       atexit(3) are not called.

       After  the  last thread in a process terminates, the process terminates as by calling exit(3) with an exit status of zero; thus, process-shared resources are released and
       functions registered using atexit(3) are called.

RETURN VALUE
       This function does not return to the caller.

  • 头文件
    #include <pthread.h>
  • 函数原型
    void pthread_exit(void *retval);
  • 参数说明
    void *retval:线程退出时传递出的参数,可以是退出值或地址,如是地址时,不能是线程内部申请的局部地址。

线程的回收、取消、分离、比较

pthread_self

作用

进程通过getpid获取自身的id参数,同样线程也有函数获取自身的id,叫做tid(thread id)

NAME
       pthread_self - obtain ID of the calling thread

SYNOPSIS
       #include <pthread.h>

       pthread_t pthread_self(void);

       Compile and link with -pthread.

DESCRIPTION
       The  pthread_self()  function  returns  the  ID of the calling thread.  This is the same value that is returned in *thread in the pthread_create(3) call that created this
       thread.

RETURN VALUE
       This function always succeeds, returning the calling thread's ID.

  • 头文件
    #include <pthread.h>
  • 函数原型
    pthread_t pthread_self(void);
  • 参数说明
  • 返回值
    函数返回调用线程的thread ID

pthread_join

作用

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

  • 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返
    回值。
  • 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存
    放的是常数PTHREAD_CANCELED。
  • 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
  • 如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。
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.

DESCRIPTION
       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 loca‐
       tion pointed to by retval.  If the target thread was canceled, then PTHREAD_CANCELED is placed in the location pointed to by retval.

       If  multiple threads simultaneously try to join with the same thread, the results are undefined.  If the thread calling pthread_join() is canceled, then the target thread
       will remain joinable (i.e., it will not be detached).

RETURN VALUE
       On success, pthread_join() returns 0; on error, it returns an error number.

  • 头文件
    #include <pthread.h>
  • 函数原型
    int pthread_join(pthread_t thread, void **retval);
  • 参数说明
    pthread_t thread:回收线程的tid
    void **retval:接收退出线程传递出的返回值
  • 返回值
    成功返回0,失败返回错误号

pthread_cancel

作用

在进程内某个线程可以取消另一个线程。

NAME
       pthread_cancel - send a cancellation request to a thread

SYNOPSIS
       #include <pthread.h>

       int pthread_cancel(pthread_t thread);

       Compile and link with -pthread.

DESCRIPTION
       The  pthread_cancel()  function  sends  a cancellation request to the thread thread.  Whether and when the target thread reacts to the cancellation request depends on two
       attributes that are under the control of that thread: its cancelability state and type.

       A thread's cancelability state, determined by pthread_setcancelstate(3), can be enabled (the default for new threads) or disabled.  If a thread has disabled cancellation,
       then  a cancellation request remains queued until the thread enables cancellation.  If a thread has enabled cancellation, then its cancelability type determines when can‐
       cellation occurs.

       A thread's cancellation type, determined by pthread_setcanceltype(3), may be either asynchronous or deferred (the default for new  threads).   Asynchronous  cancelability
       means  that  the thread can be canceled at any time (usually immediately, but the system does not guarantee this).  Deferred cancelability means that cancellation will be
       delayed until the thread next calls a function that is a cancellation point.  A list of functions that are or may be cancellation points is provided in pthreads(7).

RETURN VALUE
       On success, pthread_cancel() returns 0; on error, it returns a nonzero error number.

  • 头文件
    #include <pthread.h>
  • 函数原型
    int pthread_cancel(pthread_t thread);
  • 参数说明
    pthread_t thread:需要取消的线程的tid
  • 返回值
    成功返回0,失败返回非零的错误号

pthread_detach

作用

将线程设置为detach状态。

一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取
它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收
它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用
pthread_join,这样的调用将返回EINVAL。如果已经对一个线程调用了pthread_detach就不
能再调用pthread_join了。

NAME
       pthread_detach - detach a thread

SYNOPSIS
       #include <pthread.h>

       int pthread_detach(pthread_t thread);

       Compile and link with -pthread.

DESCRIPTION
       The  pthread_detach() function marks the thread identified by thread as detached.  When a detached thread terminates, its resources are automatically released back to the
       system without the need for another thread to join with the terminated thread.

       Attempting to detach an already detached thread results in unspecified behavior.

RETURN VALUE
       On success, pthread_detach() returns 0; on error, it returns an error number.

  • 头文件
    #include <pthread.h>
  • 函数原型
    int pthread_detach(pthread_t thread);
  • 参数说明
    pthread_t thread:需要分离的线程的tid
  • 返回值
    成功返回0,失败返回错误号

pthread_equal

作用

比较两个线程是否相等

NAME
       pthread_equal - compare thread IDs

SYNOPSIS
       #include <pthread.h>

       int pthread_equal(pthread_t t1, pthread_t t2);

       Compile and link with -pthread.

DESCRIPTION
       The pthread_equal() function compares two thread identifiers.

RETURN VALUE
       If the two thread IDs are equal, pthread_equal() returns a nonzero value; otherwise, it returns 0.

  • 头文件
    #include <pthread.h>
  • 函数原型
    int pthread_equal(pthread_t t1, pthread_t t2);
  • 参数说明
    pthread_t t1:线程1的tid
    pthread_t t2:线程2的tid
  • 返回值
    成功返回非零值,说明相等;失败返回0.

代码实现

包括pthread_create/pthread_detach/pthread_join.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
void *thr_fn(void *arg)
{
	int n = 3;
	while (n--) {
		printf("thread count %d\n", n);
	sleep(1);
	}
	return (void *)1;
}

int main(void)
{
	pthread_t tid,tid_self;
	void *tret;
	int err;
	pthread_create(&tid, NULL, thr_fn, NULL);
	tid_self = pthread_self();
	printf("thread tid is %lu\n", tid_self);//pthread_t 是 unsigned long int型
	//第一次运行时注释掉下面这行,第二次再打开,分析两次结果
	//pthread_detach(tid);
	while (1) {
		err = pthread_join(tid, &tret);
		if (err != 0)
			printf("thread %s\n", strerror(err));
		else
			printf("thread exit code %d\n", (int)tret);
		sleep(1);
	}
	return 0;
}

输出结果

在这里插入图片描述
第一行打印出线程的id号。
后面的打印中,因为while循环中,子线程的变量不停的–,直到减为0退出。
随着线程通过pthread_join回收,err =0 后获取到子线程返回参数1。
紧接着子线程已经不复存在,err不为0,无法获取子线程的信息,thread No such process。

如果将注释的pthread_detach(tid)函数放开,将得到另一个输出结果。
在这里插入图片描述
因为子线程已经设置为分离态,无法再通过join函数回收子线程资源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值