Thread and Peocess

pthread_create()

原型:

  1. int pthread_create(pthread_t* thread, pthread_attr_t* attr, void*(*start_routine)(void* ), void* args){};

其中:

thread: 标识一个线程,是一个pthread_t的变量,

  1. typedef unsigned long int pthread_t

attr: 用于设置线程的属性.这里设为空,采用默认的属性

start_routine: 当线程的资源分配成功后,线程中运行的单元,(函数指针?类似于Java中的Runnable?估计可以是代码块或者是函数.)

arg: 线程函数运行时传入的参数,可以传入控制线程的变量.

成功创建线程则函数返回0,否则返回一个error,常见的error为:

EAGAIN: 表示系统中的线程数量达到了一个上限,

EINVAL: 表示线程的属性非法.

线程创建成功后,新创建的线程按照参数start_routine和args确定一个运行函数,原来的线程在线程创建函数返回后继续运行下一段代码.

pthread_join() && pthread_exit()

pthread_join()等待线程运行结束,是阻塞函数,一直到被等待的线程结束,函数返回并回收被等待线程的资源,函数原型为:

  1. extern int pthread_join __p ((pthread_t __th, void ** __thread_return));

__th: 线程的标识符,即pthread_create()创建成功的值,

__thread_return: 线程返回值,是一个指针,用来存储被等待线程的返回值,线程可以返回一个指针.而这个参数是一个指向指针的指针,所以调用的时候通常是传递一个指针的地址.

一般来说可以先建立返回类型的指针,如int类型的指针,调用pthread_join(pt, (void*)&ret_join),就可以得到ret_join.

线程的属性

线程的属性结构

线程的属性结构体为pthread_attr_t, 在头文件<pthreadtypes.h>中:

  1. typedef struct __pthread_attr_s
  2. {
  3. int __detachstate; /**线程的终止状态*/
  4. int __schedpolicy; /**调度优先级*/
  5. struct __sched_param __schedparam; /**参数*/
  6. int __inheritsched; /**继承调度*/
  7. int __scope; /**范围*/
  8. size_t __guardsize; /**保证尺寸*/
  9. int __stackaddr_set; /**运行栈*/
  10. void *__stackaddr; /**运行栈地址*/
  11. size_t __stacksize; /**线程运行大小*/
  12. }pthread_attr_t

线程的属性不能直接设置,必须调用参数,常用的设置如线程的摘取状态,调度优先级,运行栈地址和大小,优先级等.而线程的初始化pthread_attr_init(),必须在create()前调用.

如线程的优先级状态由pthread_attr_getschedparam(),pthread_attr_setschedparam()两个函数设置,需要先get,写入,然后set.

  1. #include <sched.h>
  2. #include <pthread.h>
  3. #include <stdio.h>
  4. pthread_attr_t attr;
  5. pthread_t pt;
  6. struct sched_param sch;
  7. pthread_attr_init(&attr);
  8. pthread_attr_getschedparam(&attr, &sch);
  9. sch.sched_priority = 256;
  10. pthread_attr_setschedparam(&attr, &sch);
  11. pthread_create(&pt, &attr, (void*)start_routine, &run);

线程的绑定状态,pthread_attr_setscope(),只有两个选择PTHREAD_SCOPE_SYSTEM, PTHREAD_SCOPE_PROCESS(非绑定).

  1. pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

线程的分离状态,决定线程的终止方法,有分离和非分离两种.默认为非分离,在非分离状态下,线程只有遇到pthread_join()才是线程的结束,并释放资源;而分离线程,不需要等待其他线程,自身运行完就结束,马上释放资源.

设置函数为pthread_attr_setdetachstate():

  1. int pthread_attr_setdetachstate(pthread_attr *attr, int detachstate);

detachstate有两个选择,PTHREAD_CREATE_DETACHED对应分离线程,PTHREAD_CREATE_JOINABLE对应非分离模式.

需要注意的是,如果线程运行的相当快,设置分离模式后,可能在pthread_create()返回前就执行完毕,因此有可能再次使用create()返回的线程号会出错.

(mutex 和 信号量 晚上补充 )

文件操作

文件描述符

Linux中每一个设备文件和普通文件,都对应一个整数型的文件描述符,所有对文件的操作都可以通过文件描述符实现.同时文件描述符也是内核空间和用户空间对文件和设备操作的接口.注意:文件描述符仅在一个进程内有效,即不同进程中的同一个设备或者文件可以对应不同的文件描述符,反之亦可.

Linux下有三个已经分配的文件描述符,也可以认为是系统保留的文件描述符,分别是标准输入,标准输出,标准错误;对应数字0,1,2. 所以很多时候重定向为0,1,2时,是传递的标准IO.

Open( ) & Create( )

两者都是成功应返回一个文件描述符,原型如下:

  1. int open(const char *pathname, int flags);
  2. int open(const char *pathname, int flags, mode_t mode);

使用时,应当包含的头文件为sys/types.h, sys/stat.h, fcntl.h

pathname: 是一个字符串变量,该变量的值在不同的系统下面不同,但是通常为1024字节.而如果给出的路径长度大于该数值,系统会对字符串截断,仅选择前面的部分执行.

flag: 是设置打开文件后允许对文件操作的方式.打开文件时必须是只读(O_RDONLY),只写(O_WRONLY),读写(O_RDWR)三种状态的一种,且通常定义为0,1,2.

除了必须设定的三种读写模式之外,还可以设置一些可选的参数项,如:

O_APPEND: 每次对文件的写入都追加到文件的末尾.

O_CREAT: 如果没有文件,就创建文件,且使用此选项就必须设置第三参数mode,作为新创建的文件的权限.

O_EXCL: 查看文件是否存在,如果同时指定了O_CREAT,而且文件已经存在,会返回错误,用这种方式可以安全打开一个文件.

O_TRUNC: 将文件的长度截断为0,如果文件存在,且文件成功打开,则会将其长度截断为0.通常是对文件进行清零操作的时候,选用这个参数.

O_NONBLOCK: 设置文件打开为非阻塞形式,默认为阻塞形式,即每次读写都需要返回状态.

mode就是用户,组成员,其他成员分别对文件的可读,可写,可执行的排列组合,具体可以百度.

一个O_CREAT和O_EXCL的容错的文件读写例子:

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. int main(void){
  6. int fd = -1;
  7. char filename[] = "test.txt";
  8. /**打开文件,如果文件存在,则报错*/
  9. fd = open(filename, O_RDWR|O_CREAT|O_EXCL,S_IRWXU);
  10. if(fd == -1){
  11. /**文件已经存在,重新打开*/
  12. fd = open(filename, O_RDWR);
  13. }else{
  14. /**文件不存在,创建并打开*/
  15. }
  16. return 0;
  17. }

create()函数近似与open()的精简版本,原型为:

  1. int create(const char* pathname, mode_t mode)
  2. 也可以近似理解为:
  3. open(pathname, O_WRONLY|O_TRUNC, mode)

close()

原型为:

  1. int close(int fd);

如果不关闭文件,系统在进程退出时,会自动关闭文件,但是不会收回文件描述符的值,这样在长时间后会因为达到文件描述符的最大上限而出现文件打开错误.

read()

read()从打开文件中读取数据,需要加入unistd.h,原型为:

  1. ssize_t read(int fd, void* buf, size_t count);

从文件描述符中读取count字节,放到buf开始的缓冲区,count为0,读取为0,count大于SSIZE_MAX,结果不可预料.读取成功后,文件对应的读取位置指针向后偏移,大小为成功读取的字节数.

返回0说明达到文件末尾,返回-1代表读取错误,ssize_t可以定义为long或者为int.

write()

write()写入文件,其余参数同read().如果打开或者创建的文件带有O_APPEND属性,则每次写操作之前会将写操作的位置移动到文件的末尾.原型为:

  1. ssize_t

(write 以及之后的问题暂时不补充)

进程间的通信

普通的半双工管道

在shell中使用 '|' 来标识,而在程序中用pipe(int[])来得到.

pipe是一个单向的IPC机制,限制有两点:

  1. 在普通的匿名管道中有缓冲区的限制,一般是在include/Linux/limits.h中定义,PIPE_BUF,

    POSIX.1定义该值不得小于512字节.
  2. 管道必须建立在父子进程或者是兄弟进程之间,不能在任意的两个进程中建立.

注意: 管道的阻塞性和原子性

对于一次写入管道内的数据小于128K,则是非阻塞的,当大于128K时,会阻塞直到读完成才会返回.并且在低于512的情况下,管道的读写是原子性的,而大于该值,多个线程向pipe写会造成数据覆盖.


  1. int fd[2];
  2. int status = pipe(fd);
  3. 这里的fd中,fd[0]是读的一端的文件描述符,fd[1]是写的一端的文件描述符,而如果真的需要通过pipe进行双工通信则必须建立两个管道.
  4. 通常需要在两个线程中分别关闭一个文件描述符.(主要是因为两个进程中都拿到了fd[],所以最好拿到即关掉不属于自己这端的文件描述符)
  5. int *write_fd = &fd[1];
  6. int *read_fd = &fd[0];
  7. pid_t pid;
  8. pid = fork();
  9. if(pid == -1){
  10. printf("fork error \n");
  11. }else if(pid == 0){
  12. /*in the child process*/
  13. close(*read_fd);
  14. write(*write_fd, write_thing, write_length);
  15. }else if(pid > 0){
  16. /*in the parent process*/
  17. close(*write_fd);
  18. read(*read_fd, readbuffer, readbuffe_size);
  19. }
  20. 这里还需要注意一点,必须先调用pipe()再调用fork(),否则子进程中无法继承得到文件描述符.

Thread and Peocess的更多相关文章

  1. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  2. 记一次tomcat线程创建异常调优:unable to create new native thread

    测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...

  3. 多线程爬坑之路-Thread和Runable源码解析

    多线程:(百度百科借一波定义) 多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提 ...

  4. Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

    学习架构探险,从零开始写Java Web框架时,在学习到springAOP时遇到一个异常: "C:\Program Files\Java\jdk1.7.0_40\bin\java" ...

  5. Exception in thread "main" java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V

    在学习CGlib动态代理时,遇到如下错误: Exception in thread "main" java.lang.NoSuchMethodError: org.objectwe ...

  6. Thread.Sleep(0) vs Sleep(1) vs Yeild

    本文将要提到的线程及其相关内容,均是指 Windows 操作系统中的线程,不涉及其它操作系统. 文章索引 核心概念 Thread.Yeild       Thread.Sleep(0) Thread. ...

  7. Android笔记——Handler Runnable与Thread的区别

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run() ...

  8. Java Thread 的 sleep() 和 wait() 的区别

    Java Thread 的使用 Java Thread 的 run() 与 start() 的区别 Java Thread 的 sleep() 和 wait() 的区别       1. sleep ...

  9. Android线程管理之Thread使用总结

    前言 最近在一直准备总结一下Android上的线程管理,今天先来总结一下Thread使用. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Executo ...

随机推荐

  1. java如何写接口给别人调用

    参考:https://blog.csdn.net/greatkendy123/article/details/52818466 java web开发(二) 接口开发

  2. ECharts使用问题

    Echarts官网上给的例子,在最后有一个分号. 使用ajax请求,在eval()转化时出现错误,原因就是因为多了一个分号

  3. C#读写Access数据库、表格datagridview窗体显示代码实例

    C#读写Access数据库.表格datagridview窗体显示代码实例 最近项目中用到C#对于Access数据库表读写.mdb操作,学习了下相关的东西,这里先整理C#对于Access数据库的操作,对 ...

  4. Hibernate使用Query进行查询

    错误结果如下 Exception in thread "main" org.hibernate.hql.internal.ast.QuerySyntaxException: new ...

  5. 线性SVM与Softmax分类器

    1 引入 上一篇介绍了图像分类问题.图像分类的任务,就是从已有的固定分类标签集合中选择一个并分配给一张图像.我们还介绍了k-Nearest Neighbor (k-NN)分类器,该分类器的基本思想是通 ...

  6. 138. Copy List with Random Pointer (not do it by myself)

    A linked list is given such that each node contains an additional random pointer which could point t ...

  7. unity2d 动画

    1 资源test.jpg(如下)放入Resources文件夹 2 切割图片 点击图片,在inspector中,选择Texture Type为Sprite(2D and UI),然后点击Sprite E ...

  8. 网络工程师HCNA认证学习笔记Day1

    企业网络 企业网络远程互联是广域网WAN互联,而非互联网Internet小型企业网络:一个路由器.交换机.AP大型企业网络:核心层.汇聚层.接入层.考虑可用性.稳定性.扩展性.安全性.可管理,冗余. ...

  9. iOS7 UITableView Row Height Estimation

    This post is part of a daily series of posts introducing the most exciting new parts of iOS7 for dev ...

  10. 48个国际音标-/iː/

    /iː/ 是单元音前元音,是个长元音. ***ee,ea,ie,ei*** 1)张开你的嘴巴,好像你在微笑,露出你的牙齿,嘴唇向两边伸开,成扁平形. 2)将舌前部向硬腭尽量抬起.舌头轻微接触下齿背部. ...