Linux_线程基本函数
Linux_线程基本函数
线程库没有包含在系统库中,编译时要进行链接gcc -l pthread
线程包括主线程和次线程,线程时平等的,共享数据短,栈空间,唯一不同的是栈空间不同。
tid不要打印
2.pthread_cread(tid,&attr,func,&arg) //成功返回0,错误返回错误码
tid:线程id号;attr:线程属性(大多填写NULL,后面会祥解)
func:启动例程;args:启动例程的参数
如:pthread_create(tid,NULL,doWork,NULL);
3.pthread_join(tid,void **retval)
功能:等待线程号为tid的线程执行结束后回收线程资源,类似于进程的wait()函数,会阻塞。任何一个线程都可以回收其它线程
tid:等待回收的线程
retval:1.可以作为线程结束返回码。判断线程是否正常结束
2.接收线程结束时的返回的数据空间
4.pthread_exit(void *retval)
功能:结束线程,并返回结束码:可以用0,1表示线程是否正常返回
也可以返回一个数据的地址,方便其他线程调用
5.Pthread_cancel(tid) [A1] //成功返回0,失败返回erro
功能:对线程号为tid的线程发送取消请求
注:发送成功并不代表线程tid就会结束
原因:每个线程都有取消选项,是相应取消请求要看取消选项。
取消选项包括:可取消状态和可取消类型
【1】可取消状态包含两种:
① PTHREAD_CANCEL_ENABLE:可以被取消,但是具体行为还要看取消类型
② PTHREAD_CANCEL_DISABLE:不可以被取消
pthread_setcancelstate()://设置线程取消状态
【2】可取消类型也包括两种:
① PTHREAD_CANCEL_DEFERRED 延迟取消(调用pthread_cancel并不会立即终止线程,而是继续运行,达到某个取消点时才终止)
② PTHREAD_CANCEL_ASYNCHRONOUS 导步取消(线程可以在任何时间取消)
pthread_setcanceltype() //设置线程取消类型(理解:类似于进程上锁的机制,在这期间是不能被取消的,保证数据完整)
pthread_testcancel() //设置取消点
6.pthread_self(void) //获取线程id号
7.pthread_equal(pthread_t tid1,pthread_t tid2); //比较两个线程的id号,相等返回0,失败返回非0
8.线程退出时可以调用安排好的退出清理程序(类似于atexit)
void pthread_cleanup_push(void (*rtn)(void *),void *arg); //将清理程序入栈(清理程序安装)
//execute为0弹出不执行 非0弹出并执行
void pthread_cleanup_pop(int execute); //这两个函数成对出现,pop()可以写在return后面不执行,但必须要写。
注:当执行以下动作时调用清理函数
①.调用pthread_exit
②.响应取消请求
③.execute非零调用pop
9. int pthread_detach(pthread_t tid);[A2] //如果不关心线程返回状态,可以使线程进入分离状态,分离的线程退出时,底层资源会立即回收,不需要再调用pthread_join()来回收资源,
10.线程属性
线程的分离状态属性可以用函数pthread_detach()函数来代替
线程的栈未尾警戒缓冲区大小
线程栈最低地址
线程栈大小:当有多个线程高并发时需要设置该属性
指定stack大小不能小于 #define PTHREAD_STACK_MIN 16384
int pthread_attr_getstack(const pthread_attr_t *attr,void **stackaddr,void*size);
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,int size);//设置栈大小,但需要自己申请一块未使用的空间
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);//设置栈大小,系统自动分配空间
11.pthread_once() //在多线程中保证某件事情只被执行一次
初始化变量
pthread_once_t one=PTHREAD_ONCE_INIT;
//在线程的启动例程中调用,无论哪个线程执行,都只会执行一次
pthread_once(&one,onceEvent); //onecEvent为需要执行一次的函数,用户自己写
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1. 线程标识:
(1) 比较两个线程ID;
#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
ret-若相等则返回非0值,否则返回0值
(2) 获取线程自身ID;
#include <pthread.h>
pthread_t pthread_self(void);
ret-调用线程的线程ID
2. 线程的创建:
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, //返回线程的ID
const pthread_attr_t *restrict attr, //线程属性,默认为NULL
void *(*start_rtn)(void), //线程函数入口地址
void *restrict arg); //参数
ret-成功返回0 失败返回错误编号
3. 线程的终止:
(1) 线程只是从启动例程中返回,返回值是线程的退出码;
(2) 线程可以被同一例程中的其他线程取消;
(3) 线程调用pthread_exit。
#include <pthread.h>
void pthread_exit(void *rval_ptr);
rval_ptr是一个无类型指针,与传递给启动例程的单个参数类似,进程中的其他线程可以通过调用pthread_join函数访问到这个指针;
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
ret-成功返回0 否则返回错误编号
调用线程一直阻塞,直到指定的线程调用pthread_exit,从启动例程中返回或者被取消; 如果线程只是从它的启动例程中返回,rval_ptr将包含返回码;如果线程被取消,由rval_ptr指定的内存单元就设置为PTHREAD_CANCELED.
如果线程已经处于分离状态,pthread_t就会调用失败,返回EINVAL。
如果对线程的返回值不感兴趣,可以吧rval_prt设置为NULL。这种情况下,调用pthread_join将等待线程终止,但不获取线程的终止状态。
4. 线程取消:
#include <pthread.h>
int pthread_cancel(pthread_t tid);
ret-成功返回0 失败返回错误码
函数使得由tid标识的线程行为表现为如果调用了参数是PTHREAD_CANCELD的pthread_exit函数,但是,线程可以选择忽略取消方式或者是控制取消方式。函数并不等待线程终止,它仅仅是提出请求;
5. 线程清理处理函数:
#include <pthread.h>
void pthread_cleanup_push(void(*rtn)(void*), void *arg);
void pthread_cleanup_pop(int execute); //调用删除上次push的清理程序
当线程执行以下动作时调用清理函数,调用者参数为arg,清理函数rtn的调用顺序是由pthread_cleanup_push来安排的。
a. 调用pthread_exit;
b. 想用取消请求;
c. 用非零的execute参数调用pthread_cleanup_pop;
如果execute=0则函数不被调用;
注意正常从线程返回的时候,不会调用该清理函数;
C语言多线程pthread库相关函数说明
线程相关操作说明
一、 pthread_t
pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:
typedef unsigned long int pthread_t;[A3]
它是一个线程的标识符。
二、 pthread_create
函数pthread_create用来创建一个线程,它的原型为:
extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,
void *(*__start_routine) (void *), void *__arg));
第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL.前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。
三、 pthread_join pthread_exit
函数pthread_join用来等待一个线程的结束。函数原型为:
extern int pthread_join __P ((pthread_t __th, void **__thread_return));
第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的函数原型为:
extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));
唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return. 最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH.
在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,pthread_join和pthread_exit.下面,我们来了解线程的一些常用属性以及如何设置这些属性。
互斥锁相关
互斥锁用来保证一段时间内只有一个线程在执行一段代码。
一 pthread_mutex_init
函数pthread_mutex_init用来生成一个互斥锁。NULL参数表明使用默认属性。如果需要声明特定属性的互斥锁,须调用函数 pthread_mutexattr_init.函数 pthread_mutexattr_setpshared和函数 pthread_mutexattr_settype用来设置互斥锁属性。前一个函数设置属性pshared,它有两个取值,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者用来不同进程中的线程同步,后者用于同步本进程的不同线程。在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_ PRIVATE.后者用来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、 PTHREAD_MUTEX_RECURSIVE和PTHREAD _MUTEX_DEFAULT.它们分别定义了不同的上所、解锁机制,一般情况下,选用最后一个默认属性。
二 pthread_mutex_lock pthread_mutex_unlock pthread_delay_np
pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。
下面先来一个实例。我们通过创建两个线程来实现对一个数的递加。
view source
#include
#include
#include
#include
#define MAX 10
pthread_t thread[2];
pthread_mutex_t mut;
int number=0, i;
void *thread1()
{
printf ("thread1 : I'm thread 1\n");
for (i = 0; i < MAX; i++)
{
printf("thread1 : number = %d\n",number);
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep(2);
}
printf("thread1 :主函数在等我完成任务吗?\n");
pthread_exit(NULL);
}
void *thread2()
{
printf("thread2 : I'm thread 2\n");
for (i = 0; i < MAX; i++)
{
printf("thread2 : number = %d\n",number);[nextpage]
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep(3);
}
printf("thread2 :主函数在等我完成任务吗?\n");
pthread_exit(NULL);
}
void thread_create(void)
{
int temp;
memset(&thread, 0, sizeof(thread)); //comment1
/*创建线程*/
if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0) //comment2
printf("线程1创建失败!\n");
else
printf("线程1被创建\n");
if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0) //comment3
printf("线程2创建失败");
else
printf("线程2被创建\n");
}
void thread_wait(void)
{
/*等待线程结束*/
if(thread[0] !=0) { //comment4
pthread_join(thread[0],NULL);
printf("线程1已经结束\n");
}
if(thread[1] !=0) { //comment5
pthread_join(thread[1],NULL);
printf("线程2已经结束\n");
}
}
int main()
{
/*用默认属性初始化互斥锁*/
pthread_mutex_init(&mut,NULL);
printf("我是主函数哦,我正在创建线程,呵呵\n");
thread_create();
printf("我是主函数哦,我正在等待线程完成任务阿,呵呵\n");
thread_wait();
return 0;
}
下面我们先来编译、执行一下
引文:
falcon@falcon:~/program/c/code/ftp$ gcc -lpthread -o thread_example thread_example.c
falcon@falcon:~/program/c/code/ftp$ ./thread_example
我是主函数哦,我正在创建线程,呵呵
线程1被创建
线程2被创建
我是主函数哦,我正在等待线程完成任务阿,呵呵
thread1 : I'm thread 1
thread1 : number = 0
thread2 : I'm thread 2
thread2 : number = 1
thread1 : number = 2
thread2 : number = 3
thread1 : number = 4
thread2 : number = 5
thread1 : number = 6
thread1 : number = 7
thread2 : number = 8
thread1 : number = 9
thread2 : number = 10
thread1 :主函数在等我完成任务吗?
线程1已经结束
thread2 :主函数在等我完成任务吗?
线程2已经结束
转自:https://www.cnblogs.com/edan/p/8945518.html

浙公网安备 33010602011771号