Thread and Peocess

pthread_create()

原型:

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

其中:

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

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()等待线程运行结束,是阻塞函数,一直到被等待的线程结束,函数返回并回收被等待线程的资源,函数原型为:

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>中:

typedef struct __pthread_attr_s
{
int __detachstate; /**线程的终止状态*/
int __schedpolicy; /**调度优先级*/
struct __sched_param __schedparam; /**参数*/
int __inheritsched; /**继承调度*/
int __scope; /**范围*/
size_t __guardsize; /**保证尺寸*/
int __stackaddr_set; /**运行栈*/
void *__stackaddr; /**运行栈地址*/
size_t __stacksize; /**线程运行大小*/
}pthread_attr_t

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

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

#include <sched.h>
#include <pthread.h>
#include <stdio.h> pthread_attr_t attr;
pthread_t pt;
struct sched_param sch; pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr, &sch);
sch.sched_priority = 256;
pthread_attr_setschedparam(&attr, &sch);
pthread_create(&pt, &attr, (void*)start_routine, &run);

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

pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

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

设置函数为pthread_attr_setdetachstate():

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( )

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

int open(const char *pathname, int flags);

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的容错的文件读写例子:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h> int main(void){
int fd = -1;
char filename[] = "test.txt"; /**打开文件,如果文件存在,则报错*/
fd = open(filename, O_RDWR|O_CREAT|O_EXCL,S_IRWXU);
if(fd == -1){
/**文件已经存在,重新打开*/
fd = open(filename, O_RDWR);
}else{
/**文件不存在,创建并打开*/
} return 0;
}

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

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

close()

原型为:

int close(int fd);

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

read()

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

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属性,则每次写操作之前会将写操作的位置移动到文件的末尾.原型为:

ssize_t

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

进程间的通信

普通的半双工管道

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

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

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

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

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

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


int fd[2];
int status = pipe(fd); 这里的fd中,fd[0]是读的一端的文件描述符,fd[1]是写的一端的文件描述符,而如果真的需要通过pipe进行双工通信则必须建立两个管道.
通常需要在两个线程中分别关闭一个文件描述符.(主要是因为两个进程中都拿到了fd[],所以最好拿到即关掉不属于自己这端的文件描述符) int *write_fd = &fd[1];
int *read_fd = &fd[0]; pid_t pid;
pid = fork(); if(pid == -1){
printf("fork error \n");
}else if(pid == 0){
/*in the child process*/
close(*read_fd);
write(*write_fd, write_thing, write_length);
}else if(pid > 0){
/*in the parent process*/
close(*write_fd);
read(*read_fd, readbuffer, readbuffe_size);
}
这里还需要注意一点,必须先调用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. 2.12 Hivet中order by,sort by、distribute by和cluster by

    https://cwiki.apache.org/confluence/display/Hive/LanguageManual+SortBy 一.order by 对全局数据的排序,仅仅只有一个red ...

  2. 3.16 使用Zookeeper对HDFS HA配置自动故障转移及测试

    一.说明 从上一节可看出,虽然搭建好了HA架构,但是只能手动进行active与standby的切换: 接下来看一下用zookeeper进行自动故障转移: # 在启动HA之后,两个NameNode都是s ...

  3. crontab计划任务监控nginx服务器

    #!/bin/bash ps axu |grep 'nginx' |grep -v 'grep' &>/dev/null ] then echo "准备重启nginx....& ...

  4. Swift3.0 Set

    set的简单的使用方法 //创建一个空set var letters = Set<Character>() //数组字面量创建set,只能存放string var setColors:Se ...

  5. Codevs 1247 排排站

    1247 排排站 USACO  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description FJ的N头奶牛有一些共同 ...

  6. Tcl/Tk语言学习------拆分字符串

    字符串的拆分 前言 字符串的处理是每种语言经常会遇到的问题,tcl作为一门脚本语言自然也不例外,关于字符串的拆分,一般会有两种情况:1.使用单个字符拆分,2.使用字符串拆分. 1.使用单个字符拆分字符 ...

  7. AFN的使用

    http网络库是集XML解析,Json解析,网络图片下载,plist解析,数据流请求操作,上传,下载,缓存等网络众多功能于一身的强大的类库.最新版本支持session,xctool单元测试.网络获取数 ...

  8. 结束线程方法2 Java提供的中断机制

    package com.mozq.thread.interrupt; /** * 注意:调用interrupt()方法,并不会结束线程. * 结束线程的语义:需要我们自己使用3个中断方法构建. * * ...

  9. Sublime text3 插件ColorPicker(调色板)不能使用快捷键

    我的原因是: convertToUTF8 和 ColorPicker 快捷键冲突,convertoUTF8的默认转换GBK的快捷键 和 ColorPicker打开调色板的快捷键都是ctrl+shift ...

  10. 洛谷 P2623 物品选取

    https://www.luogu.org/problemnew/show/P2623 https://www.luogu.org/blog/test-1/solution-p2623 重点就是甲类物 ...