linux线程、进程编程,Linux系统编程8:多线程编程

1. 概念

线程是比进程更小的能独立运行的基本单位,线程基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如线程ID,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

一个线程包含以下内容:

指向当前被执行指令的指令指针;

栈;

寄存器值的集合,定义了一部分描述正在执行线程的处理器状态的值;

私有的数据区

aa493f17258f

进程与线程静态

aa493f17258f

进程与线程动态

参考

man 7 threads

2. 查看线程

命令

No.

命令

含义

1

ps -T -p

-T开启线程查看

2

top -H -p

-H开启线程查看

文件

No.

文件

含义

1

/proc/{PID}/task/

线程默认的名字和进程名相同

2

/proc/{PID}/task/{tid}/comm

线程名

3. 操作

No.

操作

函数

1

线程标识

pthread_t pthread_self(void)

2

线程创建

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

3

子线程终止

void pthread_exit(void* retval)

4

线程合并

int pthread_join(pthread_t tid, void **retval)

5

线程分离

int pthread_detach(pthread_t tid)

6

发送信号

int pthread_kill(pthread_t tid, int sig)

3.1 线程标识

pthread_t pthread_self(void)

返回值

当前线程的线程ID

说明:

线程ID打印使用%lu

pthread_self()不链接库pthread返回值为0.

linux上的线程实现就是在内核支持的基础上以POSIX thread的方式对外封装了接口。

3.2 线程创建

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

参数

No.

参数

含义

1

tidp

线程ID指针

2

attr

线程属性

示例

两个线程并发执行

#include

#include

#include

#include

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){

int i = 0;

for(;i<100;i++){

usleep(500000);

info();

}

}

int main(){

info();

pthread_t tid;

pthread_create(&tid,NULL,method,NULL);

printf("new tid:%lu\n",tid);

int i = 0;

for(;i<100;i++){

sleep(1);

info();

}

sleep(1);

}

模拟抢票

#include

#include

#include

#include

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();

}

3.3 子线程退出

子线程退出有两种方式

线程处理函数return。

调用子线程终止

void pthread_exit(void* retval)

参数

No.

参数

含义

1

retval

函数的返回指针,只要pthread_join中的第二个参数retval不是NULL,这个值将被传递给retval

用在线程回调函数中,返回线程数据

3.4 线程合并

使用valgrind试试上面的程序是否有内存泄漏?

int pthread_join(pthread_t tid, void **retval)

参数

No.

参数

含义

1

tid

被等待的线程标识符

2

retval

一个用户定义的指针,它可以用来存储被等待线程的返回值

返回值

No.

返回值

含义

1

0

成功

2

非0

错误码

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

示例

无传参的情况

#include

#include

#include

#include

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);

}

有传参的情况

#include

#include

#include

#include

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();

printf("arg:%s",arg);

}

int main(){

info();

pthread_t tid;

char test[]="hello thread";

pthread_create(&tid,NULL,method,test);

printf("new tid:%lu\n",tid);

//sleep(1);

pthread_join(tid,NULL);

}

线程参数

局部变量可以作为线程参数的情况

#include

#include

#include

#include

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();

printf("arg:%s",arg);

return "this is return value";

}

int main(){

info();

pthread_t tid;

char test[]="hello thread";

pthread_create(&tid,NULL,method,test);

printf("new tid:%lu\n",tid);

//sleep(1);

void* res = NULL;

pthread_join(tid,&res);

printf("res:%s\n",res);

}

局部变量不能作为线程参数的情况

#include

#include

#include

#include

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();

printf("arg:%s",arg);

}

pthread_t create_thread(){

pthread_t tid;

char 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);

}

只读变量可以作为线程参数的情况

#include

#include

#include

#include

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();

printf("arg:%s",arg);

}

pthread_t create_thread(){

pthread_t tid;

const char* 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);

}

堆变量可以作为线程参数的情况

#include

#include

#include

#include

#include

#include

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();

printf("arg:%s",arg);

free(arg);

}

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);

}

静态变量可以作为线程参数的情况

#include

#include

#include

#include

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();

printf("arg:%s",arg);

}

pthread_t create_thread(){

pthread_t tid;

static char 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);

}

3.5 线程分离

int pthread_detach(pthread_t tid)

参数

No.

参数

含义

1

tid

要释放线程的标识符ID

返回值

No.

返回值

含义

1

0

成功

2

非0

错误码

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

线程分离后不能使用join。

使用valgrind试试pthread_detach()的程序是否有内存泄漏?

4. 进程线程比较

4.1 接口对比

No.

Process Primitive

Thread Primitive

Description

1

getpid()

pthread_self()

获得控制流的id

2

fork()

pthread_create()

创建新的控制流

3

exit()

pthread_exit()

退出已有的控制流

4

waitpid()

pthread_join()

等待控制流并获得结束代码

4.2 特性对比

No.

特性

进程

线程

1

粒度

系统资源分配和调度的基本单位

CPU调度和分派的基本单位

2

资源

有独立的地址空间

共享进程的地址空间

3

效率

上下文切换要较慢

上下文切换较快

4

稳定性

子进程崩溃,不影响父进程与其他子进程

任何一个线程崩溃,整个程序崩溃

5 线程通信

全局变量、动态分配内存和比线程生存周期长的局部变量都可以用于线程通信。

线程通信比进程简单方便。

问题:尽然有了进程,为什么要有线程?

6. C++11 thread类

使用pthread实现简单的thread类。

#ifndef __THREAD_H

#define __THREAD_H

#include

namespace miniSTL{

class thread{

typedef pthread_t id;

typedef void* (*func_t)(void*);

typedef void (*funcv_t)();

id _id; // 线程TID

public:

thread():_id(0){}

thread(func_t func){

pthread_create(&_id,NULL,func,NULL);

}

thread(funcv_t func){

pthread_create(&_id,NULL,reinterpret_cast(func),NULL);

}

id get_id()const{

return _id;

}

void join(){

pthread_join(_id,NULL);

}

void detach(){

pthread_detach(_id);

}

};

};

#endif // __THREAD_H

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值