Linux多线程编程之基础函数

pthread_create


#include <pthread.h>
        int pthread_create(pthread_t *thread,const pthread_attr_t *attr, void*(*start_routine) (void *), void *arg);

gcc编译链接时需添加选项-pthread,phtread_create创建一个新线程;thread为线程指针,attr为线程的属性结构体指针;由指针函数start_routine()创建线程,arg作为start_routine()的参数;
  
线程的终止分为下述几种情形:
1.  调用pthread_exit()终止线程,返回退出状态;在同一进程中的调用pthread_join(),另一线程可以利用该退出状态;
 2. 由start_routine()自动终止线程;
 3. 调用pthread_cancel()终止线程;
 4. 在一个进程中调用exit(),或者初始线程在main()执行返回,都将会终止该进程内的所有线程;


attr参数指向pthread_attr_t结构体,其包含被创建的线程的属性;该结构体使用pthread_attr_init()进行初始化。如果该参数设置为NULL,那么被创建的线程将被设为默认属性;若调用pthread_create()成功,在返回前,将存储新创建的线程的标识符在一段内存中,该内存由线程指针pthread_t指向;标识符与线程一一对应,在其他线程的调用函数中可以用来指向此线程;


RETURNVALUE 返回值
若新线程创建成功, pthread_create()返回0;反之,返回错误代号,指明线程未定义;
  NOTES
新线程使用pthread_create()成功创建之后,可以使用pthread_self()查看更多关于线程标识符的信息;除了使用实时调度策略,否则若调用pthread_create(),那么调用线程或新建线程接下来的执行是不确定的;
      

线程是可被连接的或可被分离的。如果一个线程A是可分离的,那么另一个线程B就可以调用pthread_join()来等待A终止,然后获取A的退出状态。只有当一个可连接的线程终止了,也已经被连接了,且是最后一个,那么其资源将会被系统收回。当一个可分离的线程终止了,它的资源会被立即回收,此时不能通过连接线程来获取其退出状态。可分离的对某些类型的守护线程——退出状态不需要关注——是很有用的!默认情况下(pthread_creat(+,NULL,+,+)),新创建的线程都是可连接的,除非在新建时设置为可分离状态。

在Linux/x86-32系统下,堆分配给新线程的默认大小为2M。在创建线程时,为了使线程获得大于2M的存储,使用pthread_attr_setstacksize(),针对参数attr,可以显式的设置堆分配给线程的大小属性。

EXAMPLE
       The program below demonstrates the useof pthread_create(), as well as a number of other functions in the pthreadsAPI.
       In the following run, on a systemproviding the NPTL threading implementation, the stack size defaults to thevalue given by the "stack size" resource limit:
 
          $ ulimit -s
          8192            # The stack sizelimit is 8 MB (0x80000 bytes)
          $ ./a.out hola salut servus
          Thread 1: top of stack near 0xb7dd03b8; argv_string=hola
          Thread 2: top of stack near 0xb75cf3b8; argv_string=salut
          Thread 3: top of stack near 0xb6dce3b8; argv_string=servus
          Joined with thread 1; returned value was HOLA
          Joined with thread 2; returned value was SALUT
          Joined with thread 3; returned value was SERVUS
In the next run, the program explicitlysets a stack size of 1MB (using pthread_attr_setstacksize(3)) for the createdthreads:
                   //使用pthread_attr_setstacksize()显式的设置线程在堆中的大小为1MB
          $ ./a.out -s 0x100000 hola salut servus
          Thread 1: top of stack near 0xb7d723b8; argv_string=hola
          Thread 2: top of stack near 0xb7c713b8; argv_string=salut
          Thread 3: top of stack near 0xb7b703b8; argv_string=servus
          Joined with thread 1; returned value was HOLA
          Joined with thread 2; returned value was SALUT
          Joined with thread 3; returned value was SERVUS

pthread_equal

int pthread_equal(pthread_t t1,pthread_t t2);

比较两个线程的标识符;如果相等,则返回非零值,反之,返回0;

pthread_self

pthread_t pthread_self(void);

返回调用线程的标识符,同 pthread_create的存储在 pthread_t指针地址下的内容相同;
NOTE
线程标识符是不透明的,不要尝试复制或新建标识符或者在其他地方使用,这将会造成无法预知的错误;线程标识符保证在每个进程中线程的唯一,在线程被 pthread_join连接终止或者被分离的线程已经终止,那么它们的线程标识符可以被重新使用;
pthread_self返回的线程标识符同内核线程ID调用 gettid()的返回结果不一样;

sched_yield

int sched_yield(void);

使得相应线程被CPU放弃,移至静态优先队列末尾,新的线程将会运行;成功则返回0,否则返回-1;
NOTE
若在高级优先队列中,仅有一个线程A,那么执行完 sched_yield,还会再运行A,因为只有它一个啊;包含在头文件< unistd.h>
当互斥量被释放,调用sched_yield()可以将优先运行权转移至另一个线程或进程;但不能滥用;

pthread_exit

void pthread_exit(void *retval);

终止相应线程同时,通过 retval返回一个数值value;若该线程是可连接的,那么此返回值可以通过 pthread_join()用于同进程的另一个线程; pthread_cleanup_push()用于清理;当线程终止时,进程共享资源(互斥量,条件变量,信号,文件描述)都没有被释放,使用 atexit()注册的函数也没有被调用。当进程中的最后一个线程终止,进程可以通过调用 exit()来终止,并返回一个状态0;同时进程共享资源被释放, atexit()释放注册函数也被调用;
NOTE
在非主线程调用 pthread_exit可以获取其退出状态;允许其他线程继续执行,主线程可以调用 ptread_exit来终止相应线程,而不是调用 exit();
返回值指针 retval不能放置在调用的线程 stack内,因为在线程被终止后,其使用的内存不稳定;

pthread_detach

int pthread_detach(pthread_t thread);

通过 thread标记线程标识符为可分离的;当可分离线程被终止后,它的资源将自动被系统回收,不需要其他线程连接;对已经分离的线程继续进行分离将会造成不确定后果;
若分离成功,则返回0;反之,返回错误状态数字;
易错点
thread 不能是一个可连接的线程;
NOTE
一旦一个线程已经被分离了,它将不能被 pthread_join()进行连接;在 pthread_create使用 pthread_attr_setdetachstate(),设置可分离属性attr,可以新建可分离状态的线程;可分离的属性仅仅在线程被终止时,确定系统的行为(自动回收资源),但当进程使用 exit()或者主线程使用 return,则不能进行自动回收资源;
pthread_join()或者 pthread_detach()应该被每个新建的线程调用,用于在线程终止时,系统回收资源;但当进程终止时,系统将回收其内含的所有线程占用的资源;
调用例子
 pthread_detach(pthread_self());

pthread_join

int pthread_join(pthread_t thread, void **retval);

等待 thread线程终止,若其已经终止,则该函数立刻返回。但用于此函数的线程必须是可连接的;
如果 retval不是 NULL,那么 pthread_join()将复制目标线程的退出状态(即 pthread_exit()的返回值)至retval指向的地址。如果目标线程被 canceled,那么*retval将会被赋值 PTHREAD_CANCELED;
如果多个线程同时尝试连接同一个线程,将会造成不可预知的错误;如果线程调用 pthread_join()被终止,那么目标线程仍然为可连接的;(即;它不是被分离的)
若成功,则返回0;反之,返回错误状态数值;


常见错误:
EDEADLK:死锁-两个线程尝试连接彼此,或者自己连接自己;
EINVAL: thread不是一个可连接的线程;
EINVAL 已经存在另一个线程在等待连接目标线程了;
ESRCH:找不到目标线程


NOTE
当成功调用pthread_join()后,调用者可以保证目标线程的终止;
连接已经被连接的线程将导致不可预知的错误;
可连接线程被连接失败将会生成"zombie thread"。所以已经要检查连接后的返回值;因为zombie thread将消耗一定的系统资源,达到一定数量,则不能创建新的线程或新的进程;同进程的任意线程可彼此互联;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值