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. PHP 对数组数值进行排序,使用另一个容器

    <?php /* 排序方式::事实上只需要将要循环的数组进行N次循环,然后每次取最大的一个值*/ $array = array(100,25,10,258,33,48,10,5,13,58,33 ...

  2. 子查询优化成join关联查询时要注意一对多关系

    mysql> select * from t where t.id in (select t1.tid from t1); +------+ | id | +------+ | +------+ ...

  3. validate[.unobtrusive]和Bootstrap实现tooltip错误提示

    validate[.unobtrusive]和Bootstrap实现tooltip错误提示 类似的文章园子里已有,请看这里,个人感觉稍显复杂,日前也打算写一个简单的给项目用,一些关键点记录于此.最终效 ...

  4. python学习笔记21(正则表达式)

    正则表达式模式: 模式 描述 ^ 匹配的开始的 $ 匹配行尾 . 匹配除换行符的任何单个字符.使用-m选项允许其匹配换行符也是如此. [...] 匹配括号内任何单个字符 [^...] 匹配非单个字符集 ...

  5. Android Studio 单刷《第一行代码》系列 03 —— Activity 基础

    前情提要(Previously) 本系列将使用 Android Studio 将<第一行代码>(书中讲解案例使用Eclipse)刷一遍,旨在为想入坑 Android 开发,并选择 Andr ...

  6. Oralce11 客户端的安装和 PlSql Developer 的配置

    关于Oracle11服务器端安装时的配置问题我就不讲了,就是要安装DataBase1和DataBase2. 现在我来讲的是Oralce11 客户端的安装和PlSql的配置问题: 步骤一:选择图示,wi ...

  7. 1187: [HNOI2007]神奇游乐园 - BZOJ

    Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游乐场,专为旅途中疲惫的人设计. ...

  8. OD之窗口界面

  9. 初试docker以及搭建mysql on docker

    前一阵阅读了google的borg论文,在最后的related works和总结中发现了kubernetes.从论文中了解的kubernetes这个东西很有意思,按照论文所说,它的实现有希望解决an ...

  10. 几款开源的图形界面库(GUI Libraries)

    SmartWin++ 遵循BSD许可协议的C++ GUI库,建立在Windows API之上,但仍可以通过使用WineLib在Linux/xNix上使用.也支持Pocket PC和基于Windows ...