线程与进程对比

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多线程编程的更多相关文章

  1. linux高级管理第十二章--rsync

    实验部分 1.安装rsync 2.配置文件 3.配置密码 4.后续 5.为了测试,创建几个文件 配置实时同步 1.调整inotify内核参数 安装inotify-tools 测试同步 编写脚本 验证 ...

  2. 读书笔记 - js高级程序设计 - 第十二章 DOM2和DOM3

      Node类型的变化   访问元素的样式 myDiv.style.backgroundColor = "red" myDiv.style.width = "100px& ...

  3. 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条

    http://blog.csdn.net/terryzero/article/details/3797782 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条 标签: swing编程 ...

  4. 鸟哥的linux私房菜——第十二章学习(Shell Scripts)

    第十二章  Shell Scripts 1.0).什么是shell scripts? script 是"脚本.剧本"的意思.整句话是说, shell script 是针对 shel ...

  5. 读书笔记 - js高级程序设计 - 第十五章 使用Canvas绘图

    读书笔记 - js高级程序设计 - 第十三章 事件   canvas 具备绘图能力的2D上下文 及文本API 很多浏览器对WebGL的3D上下文支持还不够好   有时候即使浏览器支持,操作系统如果缺缺 ...

  6. 鸟哥的Linux私房菜——第十二章:档案的压缩与打包

    视频链接: 土豆:http://www.tudou.com/programs/view/GncwT0FJKsQ B站(推荐):http://www.bilibili.com/video/av98857 ...

  7. 第三十二章 Linux常规练习题(一)

    一.练习题一 1.超级用户(管理员用户)提示符是____,普通用户提示符是____.2.linux关机重启的命令有哪些 ?3.bash是什么?4.bash特性, 常见的bash特性有哪些?5.网卡的配 ...

  8. 第十二章 Linux三剑客之老三—grep

    一.Linux grep 命令用于查找文件里符合条件的字符串. Linux系统中的grep命令是一种功能强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来.grep全称是Global ...

  9. 【linux高级程序设计】(第九章)进程间通信-管道 1

    Linux操作系统所支持的主要进程间的通信机制. 无名管道 PIPE cat test.txt| grep hello 上面这种管道,将一个命令的输出作为另一个命令的输入,而这种管道是临时的,命令执行 ...

  10. 第十二章Linux文件系统与日志

    1.inode 包含文件的元信息(1)inode 内容:文件的字节数.拥有者的 UID.GID.文件的读写执行权限.时间戳等,但不包含文件名.文件名是储存在目录的目录项中.(2)查看文件的 inode ...

随机推荐

  1. 20145202 《信息安全系统设计基础》git安装

    git的安装 直接输入指令将其安装就可以了. 安装的时候要设置公钥,我不知道以前在windows上设置过的公钥是否还能用所以我就还是从新搞了一个. 验证可以连通 遇到的问题

  2. Android 快捷方式的创建与查询 快捷方式问题大全 获取快捷方式在Launcher数据库中的信息 Failed to find provider info for com.android.la

    /** * 创建添加快捷方式 * 其中需要设置的有: * 1. 快捷方式的标题 * 2. 快捷方式的图标 * 3. 点击快捷方式后的跳转 */ public static void createSho ...

  3. 内存压缩PK页面交换 解决内存问题谁更在行

    一台服务器能够支持的虚拟机数量通常取决于物理硬件所能够提供的可用计算资源.大多数资源, 比如处理器周期.存储I/O和网络带宽等,都能够相对简单地进行共享.这种做法的原理在于负载并不总是处于忙碌状态,因 ...

  4. 超轻量级异步JS框架,别再让嵌套影响我们的优雅代码!

    1.异步JS的重要性 随着Web平台地位的提升,霸占着浏览器的JavaScript语言也成为了世界上最流行的语言之一,甚至通过Node.js进入了服务器编程领域.JavaScript的一个重要特性便是 ...

  5. FTP使用心得

    1、创建文件夹的函数,一次只能创建一层。 2、没有现成的判断文件夹是否存在的函数,如果文件夹不存在就创建,会报异常。有以下封装好的函数。可以直接调用。 1 2 3 4 5 6 7 8 9 10 11 ...

  6. USACO Section2.1 Ordered Fractions 解题报告

    frac1解题报告 —— icedream61 博客园(转载请注明出处)---------------------------------------------------------------- ...

  7. 架构师速成5.1-小学gtd进阶 分类: 架构师速成 2015-06-26 21:17 313人阅读 评论(0) 收藏

    人生没有理想,那和咸鱼有什么区别. 有了理想如何去实现,这就是gtd需要解决的问题.简单说一下gtd怎么做? 确定你的目标,如果不能确定长期目标,至少需要一个2年到3年的目标. 目标必须是可以衡量的, ...

  8. 恢复误删除表黑科技之relay log大法

      Preface       In my previous blogs,I've demonstrated several mothods of how to rescue a dropped ta ...

  9. Canvas 图片平铺设置

    /** * 图片平铺 */ function initDemo7(){ var canvas = document.getElementById("demo7"); if (!ca ...

  10. day06_05 字典

    1.0 字典 1.1 补充知识:用id可以查找出变量的内存地址 a = 10 print(id(a)) #找出内存地址 #>>>506528496 b = 15 print(id(b ...