http://blog.chinaunix.net/uid-21084809-id-2215376.html

Processes, kernel threads, user threads, and fibers

Process

1.9.2 进程的创建

pid_t fork(void) 功能:创建子进程。

fork 被调用一次,却返回两次。**先返回parent process, 后返回child process**

它可能有三种不同的返回值:
- 在父进程中,fork返回新创建的子进程的PID;
- 在子进程中,fork返回0;
- 如果出现错误,fork返回一个负值
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h> void main()
{
pid_t pid;
/*此时仅有一个进程*/
pid=fork();
/*此时已经有两个进程在同时运行*/
if(pid<0)
printf("error in fork!");
else if(pid==0)
printf("I am the child process, ID is %d\n",getpid());
else
printf("I am the parent process,ID is %d\n",getpid());
}
$./fork_test
I am the parent process, my process ID is 1991
I am the child process, my process ID is 1992

父进程的数据空间、堆栈空间都会给子进程一个拷贝,而不是共享这些内存。在子进程中对count进行自加1的操作,但是并没有影响到父进程中的count值,父进程中的count值仍然为0


pid_t vfork(void) 功能:创建子进程,parent process与child process 共享数据段

fork与vfork区别:
1.fork要拷贝父进程的数据段;**而vfork则不需要完全拷贝父进程的数据段,子进程与父进程共享数据段。**
2.fork不对父子进程的执行次序进行任何限制;而在**vfork调用中,子进程先运行,父进程挂起** 阻塞等待
wait
waitpid

Thread

中文 pthreads

linux man page

- 3: Library functions documents the functions provided by the standard C library.

pthread_attr_destroy(3)
pthread_attr_getaffinity_np(3)
pthread_attr_getdetachstate(3)
pthread_attr_getguardsize(3)
pthread_attr_getinheritsched(3)
pthread_attr_getschedparam(3)
pthread_attr_getschedpolicy(3)
pthread_attr_getscope(3)
pthread_attr_getstack(3)
pthread_attr_getstackaddr(3)
pthread_attr_getstacksize(3)
pthread_attr_init(3)
pthread_attr_setaffinity_np(3)
pthread_attr_setdetachstate(3)
pthread_attr_setguardsize(3)
pthread_attr_setinheritsched(3)
pthread_attr_setschedparam(3)
pthread_attr_setschedpolicy(3)
pthread_attr_setscope(3)
pthread_attr_setstack(3)
pthread_attr_setstackaddr(3)
pthread_attr_setstacksize(3) pthread_cancel(3)
pthread_cleanup_pop(3)
pthread_cleanup_pop_restore_np(3)
pthread_cleanup_push(3)
pthread_cleanup_push_defer_np(3)
pthread_create(3)
pthread_detach(3)
pthread_equal(3)
pthread_exit(3)
pthread_getaffinity_np(3)
pthread_getattr_np(3)
pthread_getconcurrency(3)
pthread_getcpuclockid(3)
pthread_getname_np(3)
pthread_getschedparam(3)
pthread_join(3)
pthread_kill(3)
pthread_kill_other_threads_np(3)
pthread_rwlockattr_getkind_np(3)
pthread_rwlockattr_setkind_np(3)
pthread_self(3)
pthread_setaffinity_np(3)
pthread_setcancelstate(3)
pthread_setcanceltype(3)
pthread_setconcurrency(3)
pthread_setname_np(3)
pthread_setschedparam(3)
pthread_setschedprio(3)
pthread_sigmask(3)
pthread_sigqueue(3)
pthread_testcancel(3)
pthread_timedjoin_np(3)
pthread_tryjoin_np(3)
pthread_yield(3)
头文件:#include<pthread.h>
链接库: gcc -o test test.c -std=c11 -lpthread 线程
创建一个线程默认的状态是joinable, 如果一个线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process,即还有一部分资源没有被回收(退出状态码),
所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源pthread_cleanup_push()/pthread_cleanup_pop()(类似于wait,waitpid) 但是调用pthread_join(pthread_id)后,如果该线程没有运行结束,调用者会被阻塞. 在有些情况下我们并不希望如此,比如在Web服务器中当主线程为每个新来的链接创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的链接),这时可以在子线程中加入代码
pthread_detach(pthread_self())或者父线程调用pthread_detach(thread_id)(非阻塞,可立即返回) 这将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源。 pthread_join使一个线程等待另一个线程结束。
代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。
所有线程都有一个线程号,也就是Thread ID。其类型为pthread_t。通过调用pthread_self()函数可以获得自身的线程号。

[设置线程属性 pthread_attr_init]https://www.linux.com/learn/docs/man/3789-pthreadattrinit3

具体介绍看上面的链接的man page



thread 同步方式:

POSIX Pthreads Condition Variables API

Condition variables 对应的变量类型为:pthread_cond_t

    pthread_cond_init(condition, attr)
一个 condition variable 必须被初始化,初始化有两种方式:
静态初始化 pthread_cond_t myconvar = PTHREAD_COND_INITIALIZER;
动态初始化可以使用 pthread_cond_init,参数 condition 用于返回 pthread_cond_t 变量,参数 attr 用于指定 condition variable 的属性,NULL 表示使用默认属性。属性对象的类型为 pthread_condattr_t,condition variable 只有一个进程共享属性,用于指定 condition variable 是否可以在不同的进程间使用(并不是所有的实现都支持进程共享属性) pthread_cond_destroy(condition)
用于释放一个不再使用的 condition variable pthread_cond_wait(condition, mutex)
此函数用于阻塞调用线程,直到此 condition variable 被激发。函数调用时需要使用一个已经锁定的 mutex 作参数(此 mutex 用于保护条件相关变量),调用会导致释放 mutex(这样其他线程就可以访问条件相关变量了)。之后阻塞线程被唤醒时,对应的 mutex 又会被自动的锁定(这样此线程则可以安全访问条件相关变量了)。最后程序员不要忘记去解锁此 mutex pthread_cond_signal(condition)
用于激发 condition variable,唤醒一个等待此 condition variable 的线程 pthread_cond_broadcast(condition)
用于激发 condition variable,唤醒所有等待此 condition variable 的线程
  • 信号量(semaphore)
    信号量与其他进程间通信方式不大相同,主要用途是**保护临界资源。**
相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源。同时,进程也可以修改该标志。除了用于访问控制外,还可用于进程同步。 **信号量的分类:**
- 二值信号量:
`信号量`的值只能取0或1,类似于`互斥锁`。
但两者有不同:
`信号量`强调共享资源,只要共享资源可用,其他进程同样可以修改。
`信号量`的值;`互斥锁`更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁。 - 计数信号量:信号量的值可以取任意非负值
  • Synchronization between threads using read/write locks and barriers

  • 自旋锁(Spin lock)

自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
**其作用是为了解决某项资源的互斥使用。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远 高于互斥锁。**
虽然它的效率比互斥锁高,但是它也有些不足之处:
1、自旋锁一直占用CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着CPU,如果不能在很短的时 间内获得锁,这无疑会使CPU效率降低。
2、在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁,调用有些其他函数也可能造成死锁,如 copy_to_user()、copy_from_user()、kmalloc()等。
因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。
自旋锁的用法如下:
首先定义:spinlock_t x;
然后初始化:spin_lock_init(spinlock_t *x); //自旋锁在真正使用前必须先初始化
在2.6.11内核中将定义和初始化合并为一个宏:DEFINE_SPINLOCK(x) 获得自旋锁:spin_lock(x); //只有在获得锁的情况下才返回,否则一直“自旋”
spin_trylock(x); //如立即获得锁则返回真,否则立即返回假
释放锁:spin_unlock(x);
作用域:
信号量: 进程间同步, 线程间保护临界 共享资源
互斥锁: 线程间(用于控制访问 共享数据)
NOTICE:
The POSIX semaphore API works with POSIX threads but is not part of threads standard, having been defined in the POSIX.1b, Real-time extensions (IEEE Std 1003.1b-1993) standard. Consequently the semaphore procedures are prefixed by "sem_" instead of "pthread_".

用条件变量实现事件等待器的正确与错误做法

《Linux 多线程服务端编程:使用 muduo C++ 网络库》第 2.2 节总结了条件变量的使用要点:

条件变量只有一种正确使用的方式,几乎不可能用错。对于 wait 端:
1. 必须与 mutex 一起使用,该布尔表达式的读写需受此 mutex 保护。
2. 在 mutex 已上锁的时候才能调用 wait()。
3. 把判断布尔条件和 wait() 放到 while 循环中。 对于 signal/broadcast 端:
1. 不一定要在 mutex 已上锁的情况下调用 signal (理论上)。
2. 在 signal 之前一般要修改布尔表达式。
3. 修改布尔表达式通常要用 mutex 保护(至少用作 full memory barrier)。
4. 注意区分 signal 与 broadcast:“broadcast 通常用于表明状态变化,signal 通常用于表示资源可用。(broadcast should generally be used to indicate state change rather than resource availability。)”

归纳与总结:

- 只用非递归(non-recursive)的mutex。
- 不用 读写锁 和 信号量, 只用 互斥锁 和 条件变量。(muduo库和c++11 thread库也是只有 mutex和condition variable) mutex和condition variable 都是非常底层的同步用语,主要用来实现更高级的并发编程工具。 一个多线程程序如果大量使用mutex和condition variable来同步,基本和铅笔刀锯大树一样。
所以==>
- 线程同步的四项原则:尽量用高层同步设施(线程池、队列、倒计时)
- 使用普通的 互斥锁 和 条件变量 完成剩余的同步工作,采用RAII惯用手法(idiom)和Scoped Locking.

以下是关于顺序执行线程 Demo

题目:比如3个线程,各自输出1,2,3。 让他们按照123,123,123 这个顺序连续打印10遍

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>//bool // 线程数
#define NUM_THREADS 3
#define TCOUNT 10
#define COUNT_LIMIT 12 // 条件相关变量 count
int count = 0;
// 用于保护条件相关变量 count
pthread_mutex_t count_mutex[3];
// condition variable
pthread_cond_t count_threshold_cv[3]; int myTime = 0; void *funcA(void *id)
{
long my_id = (long)id; int i = 0;
for (i = 0; i < 10; i++) {
// 锁定条件相关变量
pthread_mutex_lock(&count_mutex[my_id]); //do something
printf("AAA myTime =%d, %ld \n", myTime++, my_id); //通知其他线程 开始作业
pthread_cond_signal(&count_threshold_cv[(my_id+1)%3]);//0+1 mod 3 = 1 // 等待 condition variable 被激发
pthread_cond_wait(&count_threshold_cv[my_id], &count_mutex[my_id]); // 释放 mutex
pthread_mutex_unlock(&count_mutex[my_id]);
}
} void *funcB(void *id)
{
long my_id = (long)id; printf("enter B(): thread %ld\n", my_id); int i = 0;
for (i = 0; i < 10; i++) {
// 锁定条件相关变量
pthread_mutex_lock(&count_mutex[my_id]); // 等待 condition variable 被激发
pthread_cond_wait(&count_threshold_cv[my_id], &count_mutex[my_id]); //do something
printf("BBB myTime =%d, %ld \n", myTime++, my_id); //通知其他线程 开始作业
pthread_cond_signal(&count_threshold_cv[(my_id + 1) % 3]);//1+1 mod 3 = 2 // 释放 mutex
pthread_mutex_unlock(&count_mutex[my_id]);
}
} void *funcC(void *id)
{
long my_id = (long)id; int i = 0;
for (i = 0; i < 10; i++) {
// 锁定条件相关变量
pthread_mutex_lock(&count_mutex[my_id]); // 等待 condition variable 被激发
pthread_cond_wait(&count_threshold_cv[my_id], &count_mutex[my_id]); //do something
printf("CCC myTime =%d, %ld \n", myTime++, my_id); //通知其他线程 开始作业
pthread_cond_signal(&count_threshold_cv[(my_id + 1) % 3]);//2+1 mod 3 = 0 // 释放 mutex
pthread_mutex_unlock(&count_mutex[my_id]);
}
} int main(int argc, char *argv[])
{
int i;
long t1 = 0, t2 = 1, t3 = 2;
pthread_t threads[3];
// pthread_attr_t attr; // 初始化 condition variable 和 mutex
pthread_mutex_init(&count_mutex[0], NULL);
pthread_mutex_init(&count_mutex[1], NULL);
pthread_mutex_init(&count_mutex[2], NULL); pthread_cond_init(&count_threshold_cv[0], NULL);
pthread_cond_init(&count_threshold_cv[1], NULL);
pthread_cond_init(&count_threshold_cv[2], NULL); // 初始化线程
// pthread_attr_init(&attr);
// pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);//default joinable
pthread_create(&threads[0], NULL, funcA, (void *)t1);
pthread_create(&threads[1], NULL, funcB, (void *)t2);
pthread_create(&threads[2], NULL, funcC, (void *)t3); // 等待所有线程结束
for (i = 0; i<NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
} printf("Main(): Waited on %d threads. Done.\n", NUM_THREADS); // 清理和退出
// pthread_attr_destroy(&attr);
pthread_mutex_destroy(&count_mutex[0]);
pthread_mutex_destroy(&count_mutex[1]);
pthread_mutex_destroy(&count_mutex[2]); pthread_cond_destroy(&count_threshold_cv[0]);
pthread_cond_destroy(&count_threshold_cv[1]);
pthread_cond_destroy(&count_threshold_cv[2]); pthread_exit(NULL);
} gcc -o TestThread TestThread.c -pthread ./TestThread

(-pthred -lpthread的区别:待续)



Fiber

process thread Fiber(linux)的更多相关文章

  1. Linux中的task,process, thread 简介

    本文的主要目的是介绍在Linux内核中,task,process, thread这3个名字之间的区别和联系.并且和WINDOWS中的相应观念进行比较.如果你已经很清楚了,那么就不用往下看了. LINU ...

  2. Android Process & Thread

    Native Service and Android Service Native Service:In every main() method of NativeService, which is ...

  3. 【OS】Process & Thread

      Process Thread 定义 资源(CPU.内存等)分配的最小单元,是程序执行时的一个实例.程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时 ...

  4. Linux Process/Thread Creation、Linux Process Principle、sys_fork、sys_execve、glibc fork/execve api sourcecode

    相关学习资料 linux内核设计与实现+原书第3版.pdf(.3章) 深入linux内核架构(中文版).pdf 深入理解linux内核中文第三版.pdf <独辟蹊径品内核Linux内核源代码导读 ...

  5. Wireshark:couldn't run dumpcap in child process(附带Linux下探索过程)

    之前都是直接使用Kali里面安装好的Wireshark和Win下的,Ubuntu的来个小计 PS:解决方法不重要,我觉得更重要的是这个摸索的过程 解决方法 # 安装wireshark sudo apt ...

  6. Kernel Page Global Directory (PGD) of Page table of Process created in Linux Kernel

    Kernel Page Global Directory (PGD) of User process created 在早期版本: 在fork一个进程的时候,必须建立进程自己的内核页目录项(内核页目录 ...

  7. Enabling Process Accounting on Linux HOWTO

    http://tldp.org/HOWTO/Process-Accounting/index.html

  8. NVIDIA---CUDA

    http://en.wikipedia.org/wiki/CUDA CUDA From Wikipedia, the free encyclopedia     CUDA Developer(s) N ...

  9. process vs thread

    process vs thread http://blog.csdn.net/mishifangxiangdefeng/article/details/7588727 6.进程与线程的区别:系统调度是 ...

随机推荐

  1. mysqlsla慢查询分析工具教程

    mysqlsla是一款帮助语句分析.过滤.和排序的功能,能够处理MySQL慢查询日志.二进制日志等.整体来说, 功能非常强大. 能制作SQL查询数据报表,分析包括执行频率, 数据量, 查询消耗等. 且 ...

  2. Oracle表连接

    一个普通的语句select * from t1, t2 where t1.id = t2.id and t1.name = 'a'; 这个语句在什么情况下最高效? 表连接分类: 1. 嵌套循环连接(N ...

  3. 每日一记:搭建Memcached + php 缓存系统

    服务器环境,Centos6.5 1.安装Memcached服务端 Yum -y install memcached 2.配置Memcached服务端用户以及自动启动服务等 将服务配置成自启动 chkc ...

  4. Ubuntu Linux启用root用户登录

    Ubuntu Linux有一个与众不同的特点,那就是初次使用时,你无法作为root来登录系统,为什么会这样?这就要从系统的安装说起.对于其他Linux系统来 说,一般在安装过程就设定root密码,这样 ...

  5. python学习笔记8(表达式和语句)

    一.print 和 import 信息 >>> print 'age:',22 # 用逗号隔开打印多个表达式 age: 22 import somemodule # 从模块导入函数 ...

  6. iOS 支付宝应用(备用参考)

    1:先与支付宝签约,获得商户ID(partner)和账号ID(seller) 2:下载相应的公钥私钥文件(加密签名用) 3:下载支付宝SDK 4:生成订单信息5:调用支付宝客户端,由支付宝客户端跟支付 ...

  7. Hibernate4.1.4配置二级缓存EHCache步骤

    1.当然首先引入EHCache相关的jar包 这些包不需要另外下载,在Hibernate官方网站下载Hibernate4.1.7的压缩包(如:hibernate-release-4.1.7.Final ...

  8. poj 3318 Matrix Multiplication 随机化算法

    方法1:暴力法 矩阵乘法+优化可以卡时间过的. 方法2:随机化 随机构造向量x[1..n],则有xAB=xC;这样可以将小运算至O(n^2). 代码如下: #include<iostream&g ...

  9. json中jobject

    Json.net codeplex :http://www.codeplex.com/Json 原本感觉Newtonsoft.Json和.net自己的JavaScriptSerializer相差无几, ...

  10. HeadFirst设计模式之命令模式

    一. 1.因为是操作经常变化,所以封装操作为command对象.You can do that by introducing “command objects” into your design. A ...