一、提出问题

问1.线程存在的意义是什么?什么时候适合使用多线程?

答1.在单进程环境中实现多任务,线程可访问其所在进程的资源,例如内存、描述符等。对于单进程,如果要完成多项任务,这些任务只能依次执行,使用多线程可以让多个任务并行执行。

问2.线程的同步和异步有什么不同?同步实现机制分别有哪些?

答2.同步,顾名思义:相同的步调,就比如我们两条腿走路,左右脚之间互相协调,有节奏进行前进。在线程这里同步的意思就是,几个线程为了完成某个任务配合地、互相制约地执行。异步的概念同样可以理解,线程之间的执行没有依赖关系。同步机制适合在。同步的实现机制:互斥量、信号量、读写锁、条件变量。

二、常用函数

①创建线程

#include<pthread.h>
int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,(void*)(*start_rtn)(void*),void *arg);

参数分析:

tidp:指向保存线程ID的变量
pthread_attr_t:设置线程属性,通常为NULL
start_rtn:该线程要运行的函数的起始地址。
arg:运行函数的参数。
返回值:成功--0,失败--出错编号

②退出线程:线程主动调用,属于正常退出的一种。

#include <pthread.h>
void pthread_exit(void *retval);

retval:指向即将退出的线程所执行的函数的返回值。这里不解的是为什么线程执行的程序的返回值要通过指针参数来返回?先放一下这个问题,或许后面会有答案。

③线程等待:让父进程等待指定的线程,直到该线程结束返回。

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

参数分析:

thread:要等待的线程ID
retval:指向要等待退出的线程的返回值,这里值得注意的是它是指针的指针。联系上边的内容,pthread_create()函数中指定的线程执行函数start_rtn()是个指针函数——返回值为指针,也就是说在函数执行到最后需要来一句类似于“return 指针”这样的语句,线程调用pthread_exit就意味着“结束返回”,也需要返回这么一个指针,这个指针就是通过pthread_exit函数的参数来设置,如此上边留下的问题就有答案了。同时,问题也来了:start_rtn()指针函数返回的指针值由谁来接受?线程结束时进程在做什么,可能执行其他线程,可能进程在等待某个线程的凯旋归来等等,嗯,如果线程刚好在等待这个线程,那么自然他可以获得线程结束时的返回值——指针,我们知道存放指针的变量叫指针的指针,所以就有了参数“void **retval”。
返回值:成功--0, 失败--错误号.

④获取线程ID:在线程中调用,获取自身线程的ID.

#include <pthread.h>
pthread_t pthread_self(void);

⑤线程资源释放:根据需要这是线程在退出之前要进行的操作。

#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void*), void *arg);

参数:routine——清除函数,arg——传给清除函数的参数。

#include <pthread.h>
void pthread_cleanup_pop(int execute);

参数:execute——0:不执行push设置的清除函数;其他值执行。

问:这两个函数如何使用?有什么作用?

答:从调用pthread_cleanup_push()开始,到调用pthread_cleanup_pop()之前,期间如果线程中有调用pthread_exit()函数、或有异常退出,都将调用清除函数。特别注意:期间如果线程是执行return语句退出的绝不执行清除函数。pthread_cleanup_pop()函数参数只要非0就可“强行”执行清除函数。在设计程序时一个push对应一个pop,遵循先进后出原则。此外,在编写程序的时候如果push和pop不成对存在,编译怎么都是通不过的。作用:防止线程异常退出造成内存泄漏。

三、例程编写测试

 #include <stdio.h>
#include <pthread.h>
#include <unistd.h> /*线程清理函数*/
void *mythread_clean(void *arg)
{
printf("%s\n",(char *)arg);
return (void *);
} /*线程执行函数*/
void *mythread(void *arg)
{
printf("running in mythread.\n"); //将线程清理函数压入清除栈两次
pthread_cleanup_push( (void*)mythread_clean,"running in mythread clean handler." );
printf("mythread push complete.\n");
//如果参数为空--主动退出线程
if(!arg)
pthread_exit((void *));
pthread_cleanup_pop(); // 打印线程接收到的字符串参数
printf("*arg:%s\n",(char *)arg);
printf("sleep......\n");
sleep();
printf("exit......\n");
pthread_exit((void *));
} int main(int argc,char *argv[])
{
int err;
pthread_t tid;
void *tret; if(argc != )
{
printf("arg error.\n");
printf("ture usage:./app xxx\n");
}
//创建线程并执行线程执行函数
err=pthread_create(&tid,NULL,mythread,argv[]);
if(err!=)
{
printf("thread create error.\n");
return -;
} //阻塞等待线程退出,并获取线程的返回值
err=pthread_join(tid,&tret);
if(err!=)
{
printf("error .... \n");
return -;
}
printf("mythread return value %d.\n",(int)tret); return ;
}

thread.c

编译要点:pthread并非Linux系统的默认库,而是POSIX线程库。在编译的时候加上“-lpthread”选项。

测试结果:

编译时的那个警告是因为程序中把一个char型指针强制转换成int型变量值。

Linux系统编程:线程控制的更多相关文章

  1. Linux系统编程——线程私有数据

    在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...

  2. linux系统编程--线程

    安装线程man page,命令:sudo apt-get install manpages-posix-dev 线程概念 什么是线程 LWP:light weight process 轻量级的进程,本 ...

  3. Linux系统编程 —线程同步概念

    同步概念 同步,指对在一个系统中所发生的事件之间进行协调,在时间上出现一致性与统一化的现象. 但是,对于不同行业,对于同步的理解略有不同.比如:设备同步,是指在两个设备之间规定一个共同的时间参考:数据 ...

  4. linux系统编程--线程同步

    同步概念 所谓同步,即同时起步,协调一致.不同的对象,对“同步”的理解方式略有不同. 如,设备同步,是指在两个设备之间规定一个共同的时间参考: 数据库同步,是指让两个或多个数据库内容保持一致,或者按需 ...

  5. Linux系统编程 —线程属性

    在之前的章节中,我们在调用pthread_create函数创建线程时,第二个参数(即线程属性)都是设为NULL,即使用默认属性.一般情况下,使用默认属性已经可以解决我们开发过程中的大多数问题. 但是, ...

  6. Linux 系统编程 学习:11-线程:线程同步

    Linux 系统编程 学习:11-线程:线程同步 背景 上一讲 我们介绍了线程的属性 有关设置.这一讲我们来看线程之间是如何同步的. 额外安装有关的man手册: sudo apt-get instal ...

  7. Linux 系统编程 学习:09-线程:线程的创建、回收与取消

    Linux 系统编程 学习:09-线程:线程的创建.回收与取消 背景 我们在此之前完成了 有关进程的学习.从这一讲开始我们学习线程. 完全的开发可以参考:<多线程编程指南> 在Linux ...

  8. Linux 系统编程 学习:10-线程:线程的属性

    Linux 系统编程 学习:10-线程:线程的属性 背景 上一讲我们介绍了线程的创建,回收与销毁:简单地提到了线程属性.这一讲我们就来具体看看,线程的属性. 概述 #include <pthre ...

  9. 读书笔记之Linux系统编程与深入理解Linux内核

    前言 本人再看深入理解Linux内核的时候发现比较难懂,看了Linux系统编程一说后,觉得Linux系统编程还是简单易懂些,并且两本书都是讲Linux比较底层的东西,只不过侧重点不同,本文就以Linu ...

  10. Linux系统编程【转】

    转自:https://blog.csdn.net/majiakun1/article/details/8558308 一.Linux系统编程概论 1.1 系统编程基石 syscall: libc:标准 ...

随机推荐

  1. URAL1991 The battle near the swamp 2017-04-12 18:07 92人阅读 评论(0) 收藏

    The battle near the swamp Gungan: Jar Jar, usen da booma!  Jar Jar: What? Mesa no have a booma!  Gun ...

  2. java并发编程实战:第二章----线程安全性

    一个对象是否需要是线程安全的取决于它是否被多个线程访问. 当多个线程访问同一个可变状态量时如果没有使用正确的同步规则,就有可能出错.解决办法: 不在线程之间共享该变量 将状态变量修改为不可变的 在访问 ...

  3. centos7 mysql 数据库备份与还原

    数据库备份 show databases; #先查看一下数据库 现在我要备份word数据库 退出mysql输入 mysqldump -u root -p word > word.sql #我把它 ...

  4. Linux 批量管理工具

    pssh/pscp(Python) ansible(Python) saltstack(Python) chef puppet(Ruby) fabric(Python)

  5. shell相关文件

    站在用户登录的角度来说,SHELL的类型: 登录式shell: 正常通常某终端登录 su - USERNAME  su -l USERNAME 非登录式shell: su USERNAME 图形终端下 ...

  6. 10-11Linux用户管理规则及用户管理函数

    用户管理: useradd, userdel, usermod, passwd, chsh, chfn, finger, id, chage 组管理: groupadd, groupdel, grou ...

  7. JQuery中DOM操作(一)

    节点操作 1.插入节点,在JQuery中插入的节点方法很多,可以满足各种不同的节点插入的情况,根据不同的插入方式分为:增加环绕节点.节点内部插入和外部插入三种方式 今天我们要讲的是增加环绕节点,它有三 ...

  8. PostgreSQL操作数据表

    1.创建表(SysUser) create table "SysUsers"( "UserId" serial, --用户Id,自增 "LoginNa ...

  9. JavaScript数组(参考资料)

    JavaScript数组的长度和元素类型都是非固定的.因为数组的长度可随时改变,并且其数据在内存中也可以不连续,所以 JavaScript 数组不一定是密集型的,这取决于它的使用方式.1.Array. ...

  10. stack和stack frame

    首先,我们先来了解下栈帧和栈的基本知识: 栈帧也常被称为“活动记录”(activation record),是编译器用来实现过程/函数调用的一种数据结构. 从逻辑上讲,栈帧就是一个函数执行的环境,包含 ...