【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 ...
随机推荐
- 机器学习tensorflow框架初试
本文来自网易云社区 作者:汪洋 前言 新手学习可以点击参考Google的教程.开始前,我们先在本地安装好 TensorFlow机器学习框架. 首先我们在本地window下安装好python环境,约定安 ...
- 剑指Offer - 九度1507 - 不用加减乘除做加法
剑指Offer - 九度1507 - 不用加减乘除做加法2013-11-29 20:00 题目描述: 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. 输入: 输入可能包 ...
- 《Cracking the Coding Interview》——第1章:数组和字符串——题目2
2014-03-18 01:30 题目:反转一个char *型的C/C++字符串. 解法:一头一尾俩iterator,向中间靠拢并且交换字符. 代码: // 1.2 Implement a funct ...
- ASP NET Core ---FluentValidation
官方文档:https://fluentvalidation.net/ 一.安装: 二.应用: 1.建立PostValidator: public class PostValidator:Abstrac ...
- 调整CodeIgniter错误报告级别
修改位置:CI根目录 index.php 为开发环境与生产环境定义错误报告级别 if (defined('ENVIRONMENT')) { switch (ENVIRONMENT) { case 'd ...
- leetcode_day03
https://leetcode-cn.com/problems/container-with-most-water/ 题目:盛水最多的容器 给定 n 个非负整数 a1,a2,...,an,每个数代表 ...
- Leetcode 659.分割数组为连续子序列
分割数组为连续子序列 输入一个按升序排序的整数数组(可能包含重复数字),你需要将它们分割成几个子序列,其中每个子序列至少包含三个连续整数.返回你是否能做出这样的分割? 示例 1: 输入: [1,2,3 ...
- linux socket c/s上传文件
这是上传文件的一个示例,可以参照自行修改成下载或者其它功能. 在上传时,需要先将文件名传到服务器端,这是采用一个结构体,包含文件名及文件名长度(可以用于校验),防止文件名乱码. client #inc ...
- 实用JS系列——面向对象中的类和继承
背景: 在最开始学习JavaScript时,我们就知道,它是一种脚本语言,也有面向对象机制.但它的面向对象继承机制是基于原型的,即Prototype.今天,我们就来找一下JS中OO的影子. 创建类 1 ...
- 再看数据库——(5)Group By与Order By
在使用sql语句时,很多人都会分不清order by与group by,其实简单的说: order by -- 排序 group by --分组 1.order by是行的排序,默认为升序. 有两种方 ...