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

  1. Lua 学习笔记(九)协同程序(线程thread)

    协同程序与线程thread差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和命令指针,同时又与其他协同程序共享全局变量和其他大部分东西.从概念上讲线程与协同程序的主要区别在于,一个具有多个线程的 ...

  2. java 线程 Thread 使用介绍,包含wait(),notifyAll() 等函数使用介绍

    (原创,转载请说明出处!谢谢--http://www.cnblogs.com/linguanh/) 此文目的为了帮助大家较全面.通俗地了解线程 Thread 相关基础知识! 目录: --线程的创建: ...

  3. Android 线程Thread的2种实现方法

    在讲解之前有以下三点要说明: 1.在Android中有两种实现线程Thread的方法: ①扩展java.long.Thread类: ②实现Runnable()接口: 2.Thread类是线程类,它有两 ...

  4. Java线程Thread的状态解析以及状态转换分析 多线程中篇(七)

    线程与操作系统中线程(进程)的概念同根同源,尽管千差万别. 操作系统中有状态以及状态的切换,Java线程中照样也有. State 在Thread类中有内部类 枚举State,用于抽象描述Java线程的 ...

  5. Asp.Net任务Task和线程Thread

    Task是.NET4.0加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化都会创建一个新的线程.任务(Task)是架构在线程之上的, ...

  6. 线程 Thread Runnable 守护线程 join MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  7. Android Framework中的线程Thread及它的threadLoop方法

    当初跟踪Camera的代码中的时候一直追到了HAL层,而在Framework中的代码看见了许很多多的Thread.它们普遍的特点就是有一个threadLoop方法.依照字面的意思应该是这个线程能够循环 ...

  8. Android 线程 thread 两种实现方法

    原文链接: http://blog.csdn.net/boyupeng/article/details/6208072 这篇文章中有三点需要提前说明一下, 一: 在android中有两种实现线程thr ...

  9. 并发基础(六) 线程Thread类的start()和run()

    start()和run()方法对于刚接触线程的人来说,会有点混淆,有点难理解,一般都会有以下疑问: 一.start( )方法 1.为什么需要start方法:它的作用是什么: start方法的作用就是将 ...

随机推荐

  1. GDB + gdbserver 远程调试android native code

    原文地址:GDB + gdbserver 远程调试android native code 作者:tq08g2z 以调试模拟器中的native library code为例. Host: ubuntuT ...

  2. 【WiFi密码破解详细图文教程】ZOL仅此一份 详细介绍从CDlinux U盘启动到设置扫描破解-破解软件论坛-ZOL中关村在线

    body { font-family: Microsoft YaHei UI,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-ser ...

  3. android中设置ListView的选中的Item的背景颜色

    ListView中没有默认的选择颜色,只有选择Item后的焦点颜色,鼠标点击时Item有颜色,放开鼠标后颜色也就没有了,要实现放开鼠标后选择项的背景还是有颜色的. 1.配置main.xml <? ...

  4. 【BZOJ 1579】 1579: [Usaco2009 Feb]Revamping Trails 道路升级 (最短路)

    1579: [Usaco2009 Feb]Revamping Trails 道路升级 Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M< ...

  5. bootstrap中可用的图标集

  6. 一个简单但详细的解释Windows文件映射读取数据文件的例子

    #include <windows.h>#include <string.h>#include <string>#include <iostream>u ...

  7. xmlns=""

    用dom4j把两个手上的element撮合到一起,dom4j就会在被加的元素上写上xmlns="",当时我也没在意,后来用户要求去掉,查了一下还不是那么容易,原来xml本身对nam ...

  8. php单元测试到底是什么东西呢?

    前言: 真正写php代码也有3年时间了,勉强算是一个php程序员, 但是,心底却一直没有底气. 都说测试驱动开发,可我连程序开发中什么是单元测试?这种基本的程序员的素养都 还不是很清楚,痛定思痛,决定 ...

  9. 根据XPATH去查看修改xml文件节点的内容

    首先给出xml文件解析的路径,然后去读取节点的内容. package com.inetpsa.eqc.threads; import java.util.List; import java.io.Fi ...

  10. Application_Start和Application_End事件执行时间

    Application_start: 第一个访问网站的用户会触发该方法. 通常会在该方法里定义一些系统变量,如聊天室的在线总人数统计,历史访问人数统计的初始化等等均可在这里定义. Applicatio ...