线程(thread)
线程(thread):
现代操作系统引入进程概念,为了并发(行)任务
1.进程之间的这种切换代价很高
2.通信方式的代价也很大
基本概念:
1.线程是比进程更小的资源单位,它是进程中的一个执行路线(分支)
2.线程同进程内其它线程共享地址空间(代码段、数据段、堆...)
3.线程也称为轻量级进程
线程特点:
1.创建一个线程比创建一个进程开销要小的多
2.线程间通信十分方便
3.线程也是一个动态的概念
4.在进程内创建多个线程,可以提高系统的并发处理能力
5.每个进程至少有一个线程(主线程、main线程)
6.进程是系统分配资源的最小单位,线程是任务高度的最小单位
7.标准C中不包括线程,需要额外的库才能实现线程
posix thread ->pthread
------------------
Linux下线程相关API
1.线程创建
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
功能:用于创建一个新线程
第一个参数:指针类型,用于存储新线程的ID(线程ID是用来唯一标识一个线程)
第二个参数:指定新创建线程的属性(栈空间、优先级等),一般给NULL表示采用默认属性
第三个参数:函数指针类型,新线程的执行处理函数
第四个参数:指针类型,作为第三个参数实参
返回值:成功返回0
失败返回错误编码
Compile and link with -pthread.
编译链接时要带上pthread库
man -k pthread 查看pthread库中的所有函数
2.线程标识
进程ID在整个系统中唯一的
线程ID在所所属的进程环境有效
pthread_t pthread_self(void);
功能:获得调用线程的ID
3.多线程之间的关系
调用pthread_create创建出来的新线程,叫子线程,原来的线程叫主线程,创建成功后两个纯线程独立运行,执行顺序是由操作系统调度。
在同一个进程间,主线程结束时,会导致其它所有子线程结束。(相互影响又相互独立)
4.线程等待
int pthread_join(pthread_t thread, void **retval);
第一个参数:线程ID
第二个参数:二级指针,用于获取线程的退出状态
返回值:成功返回0,失败返回错误码。
功能:一般此函数用于主线程中,等待thread指定的线程结束,如果调用成功,可以通过retval获取终止线程的返回值。
如果等待的线程没有结束,此函数将引起调用者阻塞。
5.线程的退出
void pthread_exit(void *retval);
功能:用于终止当前正在调用的线程,通过参数返回当前线程的退出状态
可以使用同一进程中其它线程调用pthread_join函数来获取退出状态
练习:
创建一个子线程,在子线程中计算圆的面积,圆的半径通过参数传递,计算成功后把结果返回给主线程,并打印出来。
4.线程的同步
回顾:
信号量集
信号量工作方式:
P操作 减1
V操作 加1
ftok()
semget()
semop()
semctl()
信号量与共享内存:
read.c ->创建
1.获取/创建信号量
2.初始化信号量
3.创建/获取共享内存
4.映射到进程地址空间
5.操作
占用信号量 P操作
read(quit退出)
释放信号量 V操作
6.删除信号量
7.解除映射
8.删除共享内存
write.c ->使用
1.创建/获取信号量
2.创建/获取共享内存
3.映射用户空间
4.操作
占用信号量 P操作
write (quit退出)
释放信号量 V操作
5.解除映射
struct message
{
char buf[256];
int num ;
};
--------------------------------
线程:
线程创建
pthread_t id;
pthread_create(&id,NULL,线程执行函数,void*arg);
线程终止
pthread_exit(void*retval);
线程等待
void *retval;
pthread_join(id,&retval);
线程取消
int pthread_cancel(pthread_t thread);
在别的线程中去取消别一个线程
被取消的线程可以设置自己的状态:
被取消的线程接收到别一个线程的取消请求,是接受还是忽略这个请求
如果接受,是立该进行终止,还是待某个函数的调用等
int pthread_setcancelstate(int state, int *oldstate);
第一个参数:设置最新状态
PTHREAD_CANCEL_ENABLE 允许被取消(默认状态)
PTHREAD_CANCEL_DISABLE 不允许被取消
第二个参数:获取之前的取消状态,不需要获取则给NULL
int pthread_setcanceltype(int type, int *oldtype);
第一个参数:设置最新取消类型
PTHREAD_CANCEL_DEFERRED 延迟取消(默认)
PTHREAD_CANCEL_ASYNCHRONOUS 立即取消
第二个参数:获取之前的取消类型,不需要获取则给NULL
线程分离:
int pthread_detach(pthread_t thread);
功能:用于标记参数指定的线程为分离状态
对于一个分离状态的线程来说,当该线程结束时,自动释放资源
使用默认值新创建的线程是非分离状态,不该线程退出时,不会主动释放资源,必须要其它线程pthread_join
------------------
线程同步问题:
在同一个进程的多线程之间共享所在进程的地址空间,如果多个线程同时访问一个共享资源,可能会导致数据的混乱,为了解决该问题就需要线程之间的协调,而线程之间的协调和通信叫线程的同步问题
gnum = 0;
gnum++;
lock
从内存把数据读到寄存器
在寄存器把数据加1
完成再把数据写回内存
unlock
1.信号量
1.定义信号量
sem_t sem;
2.初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem_init(&sem,0,1);
3.获取信号量 (信号量减1)
int sem_wait(sem_t *sem);
sem_wait(&sem);
4.访问共享资源
5.释放信号量
int sem_post(sem_t *sem);
sem_post(&sem);
6.如果不再使用,则销毁信号量
int sem_destroy(sem_t *sem);
sem_destroy(&sem);
练习:
创建两个线程
一个线程用来读文件
把写入的数据读出来
一个线程用来写文件
往文件中写入5个hello world
文件名从命令行传入
2.互斥量(锁)
3.条件变量
/*************************************************************************
> File Name: cancel.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Fri 12 Aug 2016 11:36:35 AM CST
************************************************************************/
#include<stdio.h>
#include<pthread.h>
pthread_t id1,id2;
void *thread1(void* arg)
{
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
while(1)
{
printf("线程1正在运行!\n");
sleep(1);
}
printf("线程1被取消\n");
return (void*)2;
}
void *thread2(void* arg)
{
printf("线程2在运行!\n");
sleep(5);
printf("线程2请求取消线程1\n");
pthread_cancel(id1);
}
int main()
{
pthread_create(&id1,NULL,thread1,NULL);
pthread_create(&id2,NULL,thread2,NULL);
void *retval;
int r;
r = pthread_join(id1,&retval);
if(r != 0)
{
perror("join");
}
else
{
printf("pthread1 join\n");
}
pthread_join(id2,NULL);
printf("thread1 retval = %d\n",(int )retval);
}
/*************************************************************************
> File Name: detach.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Fri 12 Aug 2016 02:23:07 PM CST
************************************************************************/
#include<stdio.h>
#include<pthread.h>
#include<string.h>
void *thread(void*arg)
{
int i = 5;
while(i--)
{
printf("this is thread run!\n");
sleep(1);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,thread,NULL);
pthread_detach(tid);
int res;
res = pthread_join(tid,NULL);
if(res != 0)
{
fprintf(stderr,"join:%s\n",strerror(res));
}
return 0;
}
/*************************************************************************
> File Name: pthread1.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Thu 11 Aug 2016 04:16:34 PM CST
************************************************************************/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
void *newThread(void *arg)
{
printf("我就是那个新创建的线程\n");
printf("子线程的ID :%lu,PID是%d\n",pthread_self(),getpid());
return (void*)123456;
}
int main()
{
pthread_t tid;
pthread_t mid;
int res;
void *retval;
res = pthread_create(&tid,NULL,newThread,NULL);
if(res != 0)
{
fprintf(stderr,"pthread_cread:%s",strerror(res));
exit(-1);
}
printf("主线程的ID:%lu,PID是%d\n",pthread_self(),getpid());
pthread_join(tid,&retval);
printf("线程退出状态为:%d\n",(int )(retval));
}
/*************************************************************************
> File Name: sem_read.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Fri 12 Aug 2016 09:33:14 AM CST
************************************************************************/
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<string.h>
struct sembuf buf;
int sem_p(int semid)
{
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = 0;
int r = semop(semid,&buf,1);
if(r == -1)
{
perror("sem_p");
return -1;
}
return 0;
}
int sem_v(int semid)
{
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = 0;
int r = semop(semid,&buf,1);
if(r == -1)
{
perror("sem_v");
return -1;
}
return 0;
}
struct messge
{
int num;
char msg[256];
};
int main()
{
//1.
key_t key = ftok(".",100);
if(key < 0)
{
perror("ftok");
exit(-1);
}
int semid;
semid = semget(key,1,0666 | IPC_CREAT);
if(semid < 0)
{
perror("semget");
exit(-1);
}
//2.
semctl(semid,0,SETVAL,1);
//3.
int shmid;
shmid= shmget(key,1024,0666 | IPC_CREAT);
if(shmid < 0)
{
perror("shmget");
exit(-1);
}
//4.
void *shm_addr;
shm_addr = (char*)shmat(shmid,NULL,0);
if(shm_addr == (void*)-1)
{
perror("shmat");
exit(-1);
}
struct messge *msgd;
msgd = shm_addr;
sleep(5);
//5.
char buf[256] = {0};
while(1)
{
if(sem_p(semid))
{
exit(-1);
}
printf("进入读进程:\n");
// strcpy(buf,shm_addr);
printf("消息编号是%d,读到的内容:%s\n",msgd->num,msgd->msg);
printf("离开读进程!\n\n");
if(sem_v(semid))
{
exit(-1);
}
if(strncmp(msgd->msg,"quit",4) == 0)
{
break;
}
//.
}
//6.
if(semctl(semid,0,IPC_RMID) == -1)
{
perror("semctl_rmid");
exit(-1);
}
//7.
if(shmdt(shm_addr) == -1)
{
perror("shmdt");
exit(-1);
}
//8.
if(shmctl(shmid,IPC_RMID,NULL) == -1)
{
perror("shmctl");
exit(-1);
}
return 0;
}
/*************************************************************************
> File Name: sem_read.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Fri 12 Aug 2016 09:33:14 AM CST
************************************************************************/
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<string.h>
struct message
{
int num;
char msg[256];
};
struct sembuf buf;
int sem_p(int semid)
{
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = 0;
int r = semop(semid,&buf,1);
if(r == -1)
{
perror("sem_p");
return -1;
}
return 0;
}
int sem_v(int semid)
{
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = 0;
int r = semop(semid,&buf,1);
if(r == -1)
{
perror("sem_v");
return -1;
}
return 0;
}
int main()
{
//1.
key_t key = ftok(".",100);
if(key < 0)
{
perror("ftok");
exit(-1);
}
int semid;
semid = semget(key,1,0666 | IPC_CREAT);
if(semid < 0)
{
perror("semget");
exit(-1);
}
//2.
// semctl(semid,0,SETVAL,1);//做为非创建者,不需要初始化,直接用就可
//3.
int shmid;
shmid= shmget(key,1024,0666 | IPC_CREAT);
if(shmid < 0)
{
perror("shmget");
exit(-1);
}
//4.
void *shm_addr;
shm_addr = (char*)shmat(shmid,NULL,0);
if(shm_addr == (void*)-1)
{
perror("shmat");
exit(-1);
}
struct message *msgd = shm_addr;
msgd->num = 0;
//5.
char buf[256] = {0};
while(1)
{
if(sem_p(semid))
{
exit(-1);
}
printf("进入写进程:\n");
fgets(buf,sizeof(buf),stdin);
msgd->num++;
strcpy(msgd->msg,buf);
printf("离开写进程!\n\n");
if(sem_v(semid))
{
exit(-1);
}
if(strncmp(buf,"quit",4) == 0)
{
break;
}
//.
}
//7.
if(shmdt(shm_addr) == -1)
{
perror("shmdt");
exit(-1);
}
return 0;
}
/*************************************************************************
> File Name: test.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Fri 12 Aug 2016 02:30:31 PM CST
************************************************************************/
#include<stdio.h>
#include<pthread.h>
#include <semaphore.h>
sem_t sem;
void *thread(void*arg)
{
sem_wait(&sem);
int num = (int)arg;
int i;
for(i = 0; i < 5; i++)
{
printf("这是线程%d\n",num);
sleep(1);
}
sem_post(&sem);
}
int main()
{
sem_init(&sem,0,1);
pthread_t tid1,tid2;
printf("ni ma\n");
pthread_create(&tid1,NULL,thread,(void*)1);
pthread_create(&tid2,NULL,thread,(void*)2);
pthread_join(tid1,NULL);
printf("ni er ju\n");
pthread_join(tid2,NULL);
printf("ni da ye\n");
sem_destroy(&sem);
return 0;
}
线程(thread)的更多相关文章
- Lua 学习笔记(九)协同程序(线程thread)
协同程序与线程thread差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和命令指针,同时又与其他协同程序共享全局变量和其他大部分东西.从概念上讲线程与协同程序的主要区别在于,一个具有多个线程的 ...
- java 线程 Thread 使用介绍,包含wait(),notifyAll() 等函数使用介绍
(原创,转载请说明出处!谢谢--http://www.cnblogs.com/linguanh/) 此文目的为了帮助大家较全面.通俗地了解线程 Thread 相关基础知识! 目录: --线程的创建: ...
- Android 线程Thread的2种实现方法
在讲解之前有以下三点要说明: 1.在Android中有两种实现线程Thread的方法: ①扩展java.long.Thread类: ②实现Runnable()接口: 2.Thread类是线程类,它有两 ...
- Java线程Thread的状态解析以及状态转换分析 多线程中篇(七)
线程与操作系统中线程(进程)的概念同根同源,尽管千差万别. 操作系统中有状态以及状态的切换,Java线程中照样也有. State 在Thread类中有内部类 枚举State,用于抽象描述Java线程的 ...
- Asp.Net任务Task和线程Thread
Task是.NET4.0加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化都会创建一个新的线程.任务(Task)是架构在线程之上的, ...
- 线程 Thread Runnable 守护线程 join MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Android Framework中的线程Thread及它的threadLoop方法
当初跟踪Camera的代码中的时候一直追到了HAL层,而在Framework中的代码看见了许很多多的Thread.它们普遍的特点就是有一个threadLoop方法.依照字面的意思应该是这个线程能够循环 ...
- Android 线程 thread 两种实现方法
原文链接: http://blog.csdn.net/boyupeng/article/details/6208072 这篇文章中有三点需要提前说明一下, 一: 在android中有两种实现线程thr ...
- 并发基础(六) 线程Thread类的start()和run()
start()和run()方法对于刚接触线程的人来说,会有点混淆,有点难理解,一般都会有以下疑问: 一.start( )方法 1.为什么需要start方法:它的作用是什么: start方法的作用就是将 ...
随机推荐
- Textbox服务器控件
<body> <form id="form1" runat="server"> <div> 姓名:<asp:TextB ...
- DWR 整合之Struts2.3.16
DWR 能够和任何框架结合. DWR 和 Struts 整合有 2 个层次.最基础的层次就是同时使用这两个框架,这是非常容易的,但是这样就不允许在 DWR 和 Struts 之间共享 Action 了 ...
- jQuery判断当前元素是第几个元素&获取第N个元素
假设有下面这样一段HTML代码: <ul> <li>jQuery判断当前元素是第几个元素示例</li> <li>jQuery获取第N个元素示例</ ...
- C语言写的俄罗斯方块
源:C语言写的俄罗斯方块 2014年最后一天, 任天堂将风靡全球30年的经典游戏<<俄罗斯方块>>下架. 作为全球最畅销的游戏, 其移植版本遍布各个平台. 下面这个是我去年在5 ...
- angularJS 系列(一)
angularJS 中 $scope 的原型 和 原型继承之间的细微差别是什么? 参考:http://stackoverflow.com/questions/14049480/what-are-the ...
- keystone policy.json 的学习总结
keystone的policy.json文件位于:/etc/keystone/policy.json 其内容如下: 1 { 2 "admin_required": "ro ...
- 《javascript语言精粹》——第3章对象
第三章:对象: 属性名字:可以是包括空字符串在内的任意字符串: 属性值:是除undefined值之外的任何值; [1].对象字面量: var obj={}; //空对象 var obj = new O ...
- 用DMA直接驱动GPIO,实现GPIO最高输出速率(转)
源:用DMA直接驱动GPIO,实现GPIO最高输出速率 先上图:STM32F303芯片,72M的主频 可以看到GPIO的达到了14.4M的翻转速率, 再来上代码: RCC_AHBPeriph ...
- CoordinatorLayout学习笔记
CoordinatorLayout是一个增强型的FrameLayout.它的作用有两个 作为一个布局的根布局 最为一个为子视图之间相互协调手势效果的一个协调布局 代码如下: <?xml vers ...
- IOS开发中使用AFNetworking请求网络数据
1.把AFNetworking的文件拖放到项目中(注意不同的版本方法不一样,本历程基于版本2013): 2.使用#import "AFNetworking.h"命令把AFNetwo ...