POSIX线程库pthread

pthread_create()
函数作用:创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后就开始运行相关的线程函数。
函数原型:int pthread_create(pthread_t *tidp,const pthread_attr_t *attr, void *(*start_rtn)(void*),void *arg);
参数:

  • 第一个参数为指向线程标识符的指针。

  • 第二个参数用来设置线程属性

  • 第三个参数线程运行函数的起始地址。

  • 队后一个参数是运行函数的参数。
    返回值:

  • 线程创建成功,返回0

  • 线程创建失败,返回出错编号

返回成功时,由tidp指向的内存单元被设置为新创建线程的ID,attr参数用于指定各种不同的线程属性。
新创建的线程从start_rtn函数的地址开始运行,该函数只有一个万能指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构体中,然后将结构体的地址作为arg的参数传入。

因为pthread并非Linux系统的默认库,二十POSIX线程库。在Linux中将其作为一个库来使用,因此加上-lpthread(或 -pthread)以显式链接该库。函数在执行错误时的错误信息将作为返回值返回,并不修改系统全局变量errno,当然也无法使用perror()来打印错误信息。


pthread_join()
函数作用:用来等待一个线程的结束,线程间同步的操作。
函数原型:int pthread_join(pthread_t thread, void **retval);
函数描述:pthread_join()函数以阻塞的方式等到thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread知道你过的线程必须是joinable。
参数:

  • thread:线程标识符,即线程ID
  • retval:用户定义的指针,用来储存被等待线程的返回值。
    返回值:
  • 成功返回0
  • 失败返回错误号

在Linux中,新建的线程并不是在原先的进程中,而是系统通过一个系统调用clone().该系统调用copy了一个和原先进程完全一样的进程,并在这个进程中执行线程函数。不过这个copy过程和fork不同。copy后的进程和原先的进程共享了所有的变量,运行环境。这样,原先进程中的变量变动在copy后的进程中便能体现出来


pthread_exit()
函数作用:终止调用它的线程并返回一个指向某个对象的指针。
函数原型:void pthread_exit( void * value_ptr );
参数:
value_ptr:函数的返回代码。只要pthread_join的第二个参数value_ptr不是null,这个值就会被传递给value_ptr


pthread_yield()
函数原型:int pthread_yield(void);
函数作用: pthread_yield()导致调用线程放弃CPU。线程被放置在运行队列的末尾,以保持其静态优先级,并计划另一个线程运行。
返回值:

  • 成功返回0
  • 失败返回一个错误号8

pthread_self()
函数作用:获得线程自身的ID


gettimeofday()
作用:获取当前时间按
获取函数运行时间:函数运行后的时间-函数运行前的时间


pthread_kill()
函数原型:int pthread_kill(pthread_t thread, int sig)
函数作用:向指定ID的线程发送sig信号


sigaction()函数
函数原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
函数作用:用来查询或设置信号处理方式
参数:

  • signum:指定要处理扽信号
  • act:指向信号动作结构的指针
  • oldact:指向信号动作结构的指针
struct sigaction {
    void (*sa_handler)(int);		//指向信号处理函数的地址
    void (*sa_sigaction)(int, siginfo_t *, void *);		//指向函数的指针
    sigset_t sa_mask;		
    int sa_flags;		//用于指示信号处理函数的不同选项,可以通过“|”连接不同的参数,从而实现所需的选项设置。
};

siginfo_t结构体:

struct siginfo_t {
    int si_signo;        //Signal number
    int si_errno;        //Errno value
    int si_code;         //Signal code
    pid_t si_pid;        //Sending process ID
    uid_t si_uid;        //Real user ID of sending process
    int si_status;       //Exit value or signal
    clock_t si_utime;    //User time consumed
    clock_t si_stime;    //System time consumed
    signal_t si_value;   //Signal value
    int si_int;          //POSIX.1b signal
    void *si_ptr;        //POSIX1.b signal
    void *si_addr;       //Memory location that caused fault
    int si_band;         //Band event
    int si_fd;           //File descriptor
};

pthread_attr_init()
函数原型:int pthread_attr_init(pthread_attr_t *attr);
函数作用:初始化一个线程对象的属性,需要用pthread_attr_destroy函数对其去除初始化。
参数:指向一个线程属性结构的指针,结构中的元素分别对应着新线程的运行属性。属性对象主要包括是否绑定、是否分离、堆栈地址和大小、优先级等。默认属性为非绑定、非分离、默认1MB堆栈、与父进程有相同优先级。
返回值:

  • 成功返回0
  • 失败返回错误代码

pthread_attr_destroy()
函数原型:int pthread_attr_destroy(pthread_attr_t *attr);
函数作用:销毁一个目标结构,并且使它在重新初始化之前不能重新使用。
参数:要删除的线程属性结构体指针
返回值:

  • 成功返回0
  • 错误返回错误代码



在这里插入图片描述
在这里插入图片描述
注意pthread_join函数的参数:
只要pthread_join的第二个参数value_ptr不是null,pthread_exit中的参数就会被传递给value_ptr。

注意在用循环进行创建线程且参数跟循环的层数有关的话有时会导致混乱,线程创建的快慢是不确定的,所以可能导致的所传过去的参数出现重复。

解决方法:
在每次创建完线程之后都睡眠一下。
将要传过去的参数先放在一个数组中。

多线程

可在控制线程中创建多个线程,若多个线程对控制线程所传过去的同一个参数进行修改,那么这个参数的地址空间就相当于这些线程的共享内存空间。
在这里插入图片描述

因为线程是在进程的堆栈空间中创建的,所以可以创建的线程数是有限。,可以分配给线程的空间也是有限的,接近2G。

线程池

线程池其实就是先创建能创建的所有线程,然后将没有使用到的线程放在线程池中等待,需要线程时就调用线程池中现有的线程。

注意:在运行时需要连接动态库foprnmp

在这里插入图片描述

fork() and exec()

如果在main()中调用fork(),子进程只会复制main()函数,而不复制其他线程的地址空间,
如果fork()是在其他线程中创建的,那么子进程只会复制该线程的地址空间。

若在其他进程中调用fork()会导致发生意外情况,如果该线程在退出之前没有保证子进程已经结束,那么就会导致该进程变成一个孤儿进程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值