【linux高级程序设计】(第十二章)Linux多线程编程
线程与进程对比
1.用户空间对比
2.内核空间资源对比
在创建线程时,Linux内核仍然创建一个新的PCB来标识这个线程。内核并不认为进程与线程有差别。
进程是操作系统管理资源的基本单元,线程时Linux系统调度的基本单元。
3.进程线程函数对比
创建线程
int pthread_create (pthread_t *__restrict __newthread,
__const pathread_attr_t *__restrict __attr,
void *(*__start_routine) (void *),
void *__restrict __arg)
成功返回0,失败返回非0值。
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/syscall.h>
struct message
{
int i;
int j;
}; void * hello(struct message *str)
{
printf("child, the tid = %lu, pid = %ld\n", pthread_self(),syscall(SYS_gettid));
printf("the arg.i is %d, arg.j is %d\n", str->i, str->j);
while();
} int main(int argc, char *argv[])
{
struct message test;
pthread_t thread_id;
test.i = ;
test.j = ;
pthread_create(&thread_id, NULL, (void *)*hello, &test); //创建线程
printf("parent, the tid = %lu, pid = %ld\n", pthread_self(),syscall(SYS_gettid));
pthread_join(thread_id, NULL);
}
注意,编译的时候需要加上 -lpthread
gcc -o 名字 源文件 -lphtread (无法使用perror打印错误信息,因为不修改系统全局变量errno)
void pthread_exit (void *__retval) :线程退出,与exit()函数类似
int pthread_join (pthread_t __th, void **__thread_return) :阻塞调用当前线程的线程,直到此线程退出。类似于wait函数。
第一个参数:被等待线程ID。必须等待关联线程
第二个参数:用户定义指针,存储被等待线程返回值。
int pthread_detach (pthread_t __th) :设置线程为独立线程。成功返回0.
测试线程退出时全局变量和堆变量:仍然可用
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void *helloworld(char *argc);
int main(int argc, char *argv[])
{
int error;
int *temptr;
pthread_t thread_id;
pthread_create(&thread_id, NULL, (void *)*helloworld, "helloworld");
//测试下面两者是否有区别
printf("*p = %x, p = %x\n", *helloworld, helloworld);
if(error = pthread_join(thread_id, (void**)&temptr))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
//打印子线程退出时的值
printf("temp = %x, *temp = %c\n", temptr, *temptr);
//修改堆空间 测试是否可用
*temptr = 'd';
printf("%c\n", *temptr);
free(temptr);
return ;
} void *helloworld(char *argc)
{
int *p;
p = (int *)malloc( * sizeof(int));
printf("the message is %s\n", argc);
printf("the child id is %u\n", pthread_self());
memset(p, 'c', );
printf("p = %x\n", p);
pthread_exit(p); //退出线程,堆空间首地址做为返回信息
}
可以看到,函数名 helloworld 和 *helloworld 是一样的。
线程退出时资源释放
void pthread_cleanup_push(void (*routine) (void *), void *arg) :压入清理函数栈,后进先出
void pthread_cleanup_pop(int execute) :参数为0,表示不执行弹出的清理函数;非0执行。
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
void cleanup()
{
printf("cleanup\n");
}
void *test_cancel(void)
{
pthread_cleanup_push(cleanup, NULL);
printf("test_cancel\n");
while()
{
printf("test message\n");
sleep();
}
pthread_cleanup_pop();
}
int main()
{
pthread_t tid;
//创建线程
pthread_create(&tid, NULL, (void *)test_cancel, NULL);
sleep();
//取消子线程
pthread_cancel(tid);
pthread_join(tid, NULL);
}
取消线程
条件1:线程必须可以被其他线程取消,默认可以
条件2:线程处于可取消点才能被取消。
int pthread_cancel (pthread_t __cancelthread) :向某线程发送取消操作。
int pthread_setcancelstate (int __state, int *__oldstate) :设置当前线程的可取消性, state为新状况,oldstate存储原来的状态。
PTHREAD_CANCEL_DISABLE为不可取消;
PTHREAD_CANCEL_ENABLE为可取消。(默认值)
int pthread_setcanceltype (int __type, int *__oldtype) :设置取消类型。
PTHREAD_CANCEL_ASYNCHRONOUS :可随时执行新的或未决的取消请求
PTHREAD_CANCEL_DEFERRED :在目标线程到达取消点之前,取消请求处于未决状态。(默认值)
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
void *thread_function(void *arg);
int main(int argc, char *argv[])
{
int res;
pthread_t a_thread;
void *thread_result;
//创建线程
res = pthread_create(&a_thread, NULL, thread_function, NULL);
if(res != )
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
sleep();
printf("Cancelling thread...\n");
//取消子线程
res = pthread_cancel(a_thread);
if(res != )
{
perror("Thread cancelation failed");
exit(EXIT_FAILURE);
}
printf("Waitint for thread to finish...\n");
//等待子线程结束
res = pthread_join(a_thread, &thread_result);
if(res != )
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} //新线程执行函数
void *thread_function(void *arg)
{
int i, res, j;
sleep();
//设置为不可取消
res = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if(res != )
{
perror("Thread pthread_setcancelstate failed");
exit(EXIT_FAILURE);
}
sleep();
printf("thread cancle type is disable, can't cancle this thread\n");
for(i = ; i < ; i++)
{
printf("Thread is running (%d)...\n", i);
sleep();
}
//设置为可取消
res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if(res != )
{
perror("Thread pthread_setcancelstate failed");
exit(EXIT_FAILURE);
}
printf("Now change the canclestate is ENABLE\n");
sleep();
pthread_exit();
}
线程与私有数据
如果需要每个线程有自己私有的全局变量,可以使用同名而不同内存地址的线程私有数据结构,成为私有数据TSD。
int pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)) :创建线程私有数据,地址赋值给key. 所有线程对key可见,但线程可以根据自己的需要,在key中填入不同值,相当于同名不同值。第二个参数表示线程退出时key的资源释放函数。
int pthread_key_delete(pthread_key_t key) :注销一个TSD,不调用destr_sunction?
int pthread_setspecific (pthread_key_t key, const void *pointer) :将pointer的值与key相关联。
void * pthread_getspecific (pthread_key_t key) :读取与key相关联的数据
全局变量测试,不使用TSD的情况。
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
//全局变量,初值100
int key = ;
void *helloworld_one(char * argc)
{
printf("the message is %s\n", argc);
//修改值为10
key = ;
printf("key=%d, the child id is %u\n", key, pthread_self());
return ;
}
void *helloworld_two(char * argc)
{
printf("the message is %s\n", argc);
//休眠,让另一个线程先修改值
sleep();
printf("key=%d, the child id is %u\n", key, pthread_self());
return ;
}
int main()
{
pthread_t thread_id_one;
pthread_t thread_id_two;
pthread_create(&thread_id_one, NULL, (void *)*helloworld_one, "helloworld");
pthread_create(&thread_id_two, NULL, (void *)*helloworld_two, "helloworld");
pthread_join(thread_id_one, NULL);
pthread_join(thread_id_two, NULL);
}
两个线程打印的都是修改后的值
使用TSD,值不同
#include<stdio.h>
#include<pthread.h>
//线程私有数据类型
pthread_key_t key;
void echomsg(void *t)
{
printf("destructor excuted in thread %u, param=%u\n",pthread_self(),((int *)t));
}
void * child1(void *arg)
{
int i = ;
int tid = pthread_self();
printf("\nset key value %d in thread %u\n", i, tid);
//修改私有数据值
pthread_setspecific(key, &i);
//等待让另一个线程修改值
printf("thread one sleep 2 until thread two finish\n");
sleep();
printf("\nthread %u returns %d, add is %u\n", tid, *((int *)pthread_getspecific(key)),
(int *)pthread_getspecific(key));
}
void * child2(void *arg)
{
int temp = ;
int tid = pthread_self();
printf("\nset key value %d in thread %u\n", temp, tid);
//修改私有数据值
pthread_setspecific(key, &temp);
sleep();
printf("\nthread %u returns %d, add is %u\n", tid, *((int *)pthread_getspecific(key)),
(int *)pthread_getspecific(key));
}
int main(void)
{
pthread_t tid1, tid2;
pthread_key_create(&key, echomsg);
pthread_create(&tid1, NULL, (void *)child1, NULL);
pthread_create(&tid2, NULL, (void *)child2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_key_delete(key);
return ; }
【linux高级程序设计】(第十二章)Linux多线程编程的更多相关文章
- linux高级管理第十二章--rsync
实验部分 1.安装rsync 2.配置文件 3.配置密码 4.后续 5.为了测试,创建几个文件 配置实时同步 1.调整inotify内核参数 安装inotify-tools 测试同步 编写脚本 验证 ...
- 读书笔记 - js高级程序设计 - 第十二章 DOM2和DOM3
Node类型的变化 访问元素的样式 myDiv.style.backgroundColor = "red" myDiv.style.width = "100px& ...
- 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条
http://blog.csdn.net/terryzero/article/details/3797782 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条 标签: swing编程 ...
- 鸟哥的linux私房菜——第十二章学习(Shell Scripts)
第十二章 Shell Scripts 1.0).什么是shell scripts? script 是"脚本.剧本"的意思.整句话是说, shell script 是针对 shel ...
- 读书笔记 - js高级程序设计 - 第十五章 使用Canvas绘图
读书笔记 - js高级程序设计 - 第十三章 事件 canvas 具备绘图能力的2D上下文 及文本API 很多浏览器对WebGL的3D上下文支持还不够好 有时候即使浏览器支持,操作系统如果缺缺 ...
- 鸟哥的Linux私房菜——第十二章:档案的压缩与打包
视频链接: 土豆:http://www.tudou.com/programs/view/GncwT0FJKsQ B站(推荐):http://www.bilibili.com/video/av98857 ...
- 第三十二章 Linux常规练习题(一)
一.练习题一 1.超级用户(管理员用户)提示符是____,普通用户提示符是____.2.linux关机重启的命令有哪些 ?3.bash是什么?4.bash特性, 常见的bash特性有哪些?5.网卡的配 ...
- 第十二章 Linux三剑客之老三—grep
一.Linux grep 命令用于查找文件里符合条件的字符串. Linux系统中的grep命令是一种功能强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来.grep全称是Global ...
- 【linux高级程序设计】(第九章)进程间通信-管道 1
Linux操作系统所支持的主要进程间的通信机制. 无名管道 PIPE cat test.txt| grep hello 上面这种管道,将一个命令的输出作为另一个命令的输入,而这种管道是临时的,命令执行 ...
- 第十二章Linux文件系统与日志
1.inode 包含文件的元信息(1)inode 内容:文件的字节数.拥有者的 UID.GID.文件的读写执行权限.时间戳等,但不包含文件名.文件名是储存在目录的目录项中.(2)查看文件的 inode ...
随机推荐
- ansible-1
ansible与salt对比: 相同: 都是为了同时在多台机器上执行相同的命令 都是python开发 不同: agent(saltstack需要安装.ansible不需要) 配置(salt配置麻烦,a ...
- tp事务处理
数据库事务处理见手册 逻辑事务处理 Model->startTrans(); // 开启事务 if(操作失败) { Model->rollback(); // 回滚 }else { Mod ...
- Java与Scala的两种简易版连接池
Java版简易版连接池: import java.sql.Connection; import java.sql.DriverManager; import java.util.LinkedList; ...
- 三 APPIUM GUI讲解(Windows版)
本文本转自:http://www.cnblogs.com/sundalian/p/5629386.html APPIUM GUI讲解(Windows版) Windows版本的APPIUM GUI有 ...
- 孤荷凌寒自学python第六十天在windows10上搭建本地Mongodb数据服务
孤荷凌寒自学python第六十天在windows10上找搭建本地Mongodb数据服务 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第六天.成功在本地搭建了windows ...
- HDU 4731 Minimum palindrome (找规律)
M=1:aaaaaaaa…… M=2:DFS+manacher, 暴出N=1~25的最优解,找规律.N<=8的时候直接输出,N>8时,头两个字母一定是aa,剩下的以aababb循环,最后剩 ...
- Eureka 使用Spring cloud config 管理中心启动
Config 工程创建之后,Eureka就可以使用Git上的配置启动服务了. Git 服务器的搭建这里就不细说了(自行解决),下面是我上传再git的配置文件: 创建EurekaServer项目(eur ...
- Linux networkmanager
我们开发的网络,出于保密,只能叫XXX网络,或者我更倾向于称之为WTF-network 由于经常处于封闭的环境,刚一接触新一点的世界,总是有那么一点猝不及防.最近发现配置的静态路由经常消失,经发现是n ...
- Java 虚拟机类加载机制
看到这个题目,很多人会觉得我写我的java代码,至于类,JVM爱怎么加载就怎么加载,博主有很长一段时间也是这么认为的.随着编程经验的日积月累,越来越感觉到了解虚拟机相关要领的重要性.闲话不多说,老规矩 ...
- POJ 1523 SPF 求割点的好(板子)题!
题意: 给个无向图,问有多少个割点,对于每个割点求删除这个点之后会产生多少新的点双联通分量 题还是很果的 怎么求割点请参考tarjan无向图 关于能产生几个新的双联通分量,对于每个节点u来说,我们判断 ...