多线程编程

来源:互联网 发布:人工智能技术专业 编辑:程序博客网 时间:2024/06/07 02:34

概念:

进程内的一个执行单元,执行的一段程序片段。共享全局变量。(和主函数同时执行的子函数就是一个线程)(hello world程序,可以说是一个进程,也可以说是一个线程)。

参考手册:

man  7  threads

查看线程:

命令:

ps  -T  -p  <pid>————查看该pid的线程

top  -H  -p  <pid>————开启线程查看

htop——设置:F2(开启“树状视图”查看)(开启“显示自定义线程”选项)F10(退出设置)

文件:

/proc/PID/task/————线程默认的名字和进程名相同

/proc/PID/task/comm——线程名

PS:PID为要查的PID号,没有PID这个文件夹。

获取线程标识:

pthread_t  pthread_self(void);

返回值——当前线程的线程ID,用%lu打印。

获取/设置线程名字:

int  prctl(int option,unsigned long arg2);

option:

PR_GET_NAME——获取当前线程的名字

PR_SET_NAME——设置当前线程名字(宏定义为9)

arg2:

线程名的长度最大为15字节,且应该以‘\0’结尾(共计最多16个字符)

返回值:

0——成功

-1——出错

代码:

#include <stdio.h>#include <unistd.h>#include <pthread.h>#include <sys/prctl.h>int main(){printf("PID:%d,TID:%lu\n",getpid(),pthread_self());char name[16] = {0};prctl(PR_SET_NAME,"test");prctl(PR_GET_NAME,name);printf("TNAME:%s\n",name);}


创建进程:

int pthread_create(pthread_t* tidp,pthread_attr* attr,void* (*start_rtn)(void),void* arg);

tidp:

线程ID指针。

start_rtn:

函数指针。

arg:

start_rtn指向函数的形参。

返回值:

0——成功

非0——出错

attr:

写NULL即可。

代码:

#include <unistd.h>#include <pthread.h>#include <sys/prctl.h>int info(){printf("PID:%d,TID:%lu",getpid(),pthread_self());char name[16] = {0};prctl(PR_GET_NAME,name);printf("TNAME:%s\n",name);}void* method(void* arg){info();}int main(){info();printf("PID:%d,TID:%lu\n",getpid(),pthread_self());pthread_t tid;pthread_create(&tid,NULL,method,NULL);printf("new tid:%lu\n",tid);sleep(1);}


正常终止线程:

子线程:

1.return:

线程处理函数。

2.void pthread_exit(void* retval);

函数的返回指针,用pthread_join函数的第二个参数进行接收。(用在线程回调函数中,返回线程数据)

主线程:

1.线程合并:

可由其他线程终止,回收资源。

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

tid——被等待的线程标识符。

retval——一个用户定义的指针,可以用来存储被等待进程的返回值。

返回值——0为成功,非0为错误码。

代码:

#include <pthread.h>#include <sys/prctl.h>int info(){printf("PID:%d,TID:%lu",getpid(),pthread_self());char name[16] = {0};prctl(PR_GET_NAME,name);printf("TNAME:%s\n",name);}void* method(void* arg){sleep(5);info();}int main(){info();pthread_t tid;pthread_create(&tid,NULL,method,NULL);printf("new tid:%lu\n",tid);//sleep(1);pthread_join(tid,NULL);}

2.线程分离:

不能被其他线程终止,存储资源在它终止时由系统自动回收释放。

int pthread_detach(pthread_t tid);

tid——要释放线程的标识符ID

返回值——0为成功,非0为错误码。

代码:

#include <stdio.h>#include <unistd.h>#include <pthread.h>#include <sys/prctl.h>#include <string.h>#include <errno.h>int info(){printf("PID:%d,TID:%lu",getpid(),pthread_self());char name[16] = {0};prctl(PR_GET_NAME,name);printf("TNAME:%s\n",name);}void* method(void* arg){sleep(15);info();printf("arg:%s",arg);}pthread_t create_thread(){pthread_t tid;    static char test[] = "Hello thread";pthread_create(&tid,NULL,method,(void*)test);pthread_detach(tid);return tid;}int main(){info();pthread_t tid;//char test[]="hello thread";//pthread_create(&tid,NULL,method,test);tid = create_thread();printf("new tid:%lu\n",tid);//sleep(1);int err;if((err = pthread_join(tid,NULL))!=0){fprintf(stderr,"pthread_join error:%s",strerror(err));return 1;}}


并发度:

线程并发数。

设置并发数——int  pthread_setconcurrency(int  level);

level——要设置的线程并发数。
返回值——0为成功;非0为错误号。

获取并发数——int  pthread_getconcurrency(void);

返回值:前面有设置时为level数;否则为0。

代码:

#include <pthread.h>#include <sys/prctl.h>long ticket = 1000000;void* method(void* arg){while(ticket > 0){ticket--;printf("%lu get a ticket, leave %d\n",pthread_self(),ticket);//sleep(1);}}int main(){pthread_t tid;pthread_setconcurrency(5);pthread_create(&tid,NULL,method,NULL);pthread_create(&tid,NULL,method,NULL);pthread_create(&tid,NULL,method,NULL);pthread_create(&tid,NULL,method,NULL);pthread_create(&tid,NULL,method,NULL);pause();}

自动释放资源:

void  pthread_cleanup_push(void(*routine)(void*),void* arg);

void  pthread_cleanup_pop(execute);

PS:execute通常为0;两个函数要配套使用(宏定义时分别包含左右大括号);routine为free。

代码:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <pthread.h>#include <sys/prctl.h>int info(){printf("PID:%d,TID:%lu",getpid(),pthread_self());char name[16] = {0};prctl(PR_GET_NAME,name);printf("TNAME:%s\n",name);}void* method(void* arg){pthread_cleanup_push(free,arg);sleep(5);info();printf("arg:%s",arg);//free(arg);pthread_cleanup_pop(0);}pthread_t create_thread(){pthread_t tid;char* test = malloc(BUFSIZ);strcpy(test,"Hello thread");pthread_create(&tid,NULL,method,(void*)test);return tid;}int main(){info();pthread_t tid;//char test[]="hello thread";//pthread_create(&tid,NULL,method,test);tid = create_thread();printf("new tid:%lu\n",tid);//sleep(1);pthread_join(tid,NULL);}

线程取消:

取消点:如果线程接收到取消信号,系统默认,到达指定位置才能取消。

设置取消点——void  pthread_testcancel(void);

PS:许多函数默认自带取消点(printf()/sleep()),在man 7 pthreads中查看详情。

发送取消信号:

int  pthread_cancel(pthread_t thread);

thread——要结束的线程ID。

返回值——0为成功,否则失败。

设置当前线程的取消状态:

int pthread_setcancelstate(int state,int*  oldstate);

state:

PTHREAD_CANCEL_ENABLE——允许取消(默认)

PTHREAD_CANCEL_DISABLE——禁用取消(谁都无法取消该线程,传信号没用,即使是强制取消也没用)

oldstate——之前的取消状态。

设置当前线程的取消类型:

int pthread_setcanceltype(int type,int*  oldtype);

type:

PTHREAD_CANCEL_DEFFERED——————取消点退出(默认)

PTHREAD_CANCEL_ASYNCHRONOUS———立即退出(强制取消)

代码:

#include <stdio.h>#include <pthread.h>long count = 0;void* default_func(void* arg){for(;;){pthread_testcancel();count++;}}void* disable_func(void* arg){pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);for(;;){pthread_testcancel();count++;}}void* force_func(void* arg){pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS,NULL);for(;;){count++;}}void* disable_force_func(void* arg){pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS,NULL);for(;;){count++;}}void* watch(void* arg){for(;;){sleep(1);printf("count:%d\n",count);}}void* cancel(void* arg){sleep(5);pthread_t* ptid = arg;printf("cancel %lu\n",ptid[0]);pthread_cancel(ptid[0]);}int main(int argc,char* argv[]){typedef void* (*Func)(void*); Func funcs[3] = {default_func,watch,cancel}; int c;while((c=getopt(argc,argv,"dp"))!=-1){switch(c){case 'd':funcs[0] = (funcs[0] == default_func?disable_func:disable_force_func);break;case 'p':funcs[0] = (funcs[0] == default_func?force_func:disable_force_func);break;}}pthread_t tids[3];int i=0;for(;i<3;i++){pthread_create(&tids[i],NULL,funcs[i],&tids);printf("create thread %lu\n",tids[i]);}for(i=0;i<3;i++){pthread_join(tids[i],NULL);}}

发送信号:

发送的信号对所有线程都起作用!

int pthreead_kill(pthread_t tid,int sig);

tid——线程ID

sig——信号:

0———保留信号,用来测试线程是否存在。

正数——系统调用信号或自定义信号。

返回值:

0————调用成功

ESRCH——线程不存在

EINVAL——信号不合法

代码:

if(0 != pthread_kill(ptid[0].tid,0)){printf("%lu dead\n",ptid[0].tid);break;}else{printf("%lu live\n",ptid[0].tid);}