Threads
update Oct 6,2017 15:42
linux进程间通信方式demo汇总: 这是一个不错的repo,值得一看。
关于 address space 和 task 以及 lightweight process
address space 大概相当于 process, task 大概相当于 thread,lightweight process 是 thread 的别称。
关于 process 和 thread
这里 有一个关于进程和线程区别的讨论。
总结一下,在多进程多线程模型中,processes are used to group resources together; Threads are the entities scheduled for execution on the CPU.
具体而言,process 包括了:
- an memory map (包括 data(global),stack,heap, text);
- a process control block (linux中的 task_struct)(包括pid,state,pc等很多内容);
而 thread 从属于 process。一个process下的所有 threads 共享了 process 的 memory map中的 (data(global),heap, text),而同时每个 thread 拥有自己的 stack 和 thread control block(包括pc 和 register value)。
关于 TCB (Thread control block)
TCB 包括了:
- pointer to parent PCB;
- PC/registers for thread;
- stack location in memory map;
与 process 相比的优势
- threads之间的通信方式更加灵活(more options than with pipes)。
- 比 pipe 快,因为 pipe 存储在 kernel memory 中。
- 创建 thread 比创建 process 快十倍。
- terminate 也快。
- 同一 process 的 threads 间切换也比 process 快。
关于 mutex_lock
lock 和 unlock 都是在 user mode 完成的,只有当需要 block thread 的时候会进入 kernel mode。
应用
Hiding latency for multiple I/O requests; (optimize run time)
- Make multiple requests to web server, get answer asynchronously, one per thread.
- fork-join parallelism in web browser.
- a file system.
Producer / consumer program architecture; (simplify coding)
课上小程序示例分析
简单创建一个thread,用pthread_join回收,阻塞 对于这段代码,起初对于 pthread_join() 所接收的二级指针参数 (void **)&retptr
有所疑问,但是仔细想来就明白了。因为我们需要让retptr等于thread_routine的返回值,而其返回值是一个 void * ret
,为了令retptr == ret
,我们需要传入 &retptr
,此时 &retptr
的类型就变成了 void**
。
#include "header.h"
struct inputdata {
char name[20];
} ;
struct outputdata {
int idno;
} x ;
void *threaded_routine (void * v) {
struct inputdata *d = (struct inputdata *)v;
printf ("hello from the thread!\n");
printf ("my name is %s\n",d->name);
sleep(5);
printf ("setting idno\n");
x.idno = 42;
printf ("bye from the thread!\n");
return (void *) &x;
}
main() {
pthread_t thread;
printf("hello from the parent... creating thread\n");
struct inputdata input;
strcpy(input.name,"George");
struct outputdata *retptr;
if (pthread_create( &thread, NULL, threaded_routine, (void *)&input)==0) {
// 因为要改动 retptr 的值(令其等于routine返回的(void*)&x), 所以必须使用二级指针
pthread_join(thread,(void **)&retptr);
printf("got id number %d\n", retptr->idno);
} else {
printf("could not create thread!\n");
}
printf("bye from the parent\n");
}
Threads race condition 在routine中for loop 的前部分的 y=x 之后会sleep,此时切换执行其他thread,如此一来之后执行的x=y就会覆盖其他thread已经改过的x,导致最终x不会加到30;
int x=0;
void *threaded_routine (void * v) {
const int *n = (int *)v;
int i;
for (i=0; i<10; i++) {
int y=x;
y++;
printf("%d: y=%d\n",*n,y);
sleep(1);
x=y;
printf("%d: x=%d\n",*n,x);
}
}
main()
{
pthread_t thread1, thread2, thread3;
void *retptr;
int n1=1,n2=2,n3=3;
pthread_create( &thread1, NULL, threaded_routine, (void *)&n1);
pthread_create( &thread2, NULL, threaded_routine, (void *)&n2);
pthread_create( &thread3, NULL, threaded_routine, (void *)&n3);
printf("joining thread 1\n");
pthread_join(thread1,(void **)&retptr);
printf("joining thread 2\n");
pthread_join(thread2,(void **)&retptr);
printf("joining thread 3\n");
pthread_join(thread3,(void **)&retptr);
printf ("x = %d (should be 30)\n",x);
}
Using mutex_lock mutex_lock 的原理基于当pthread_mutex_lock() 的参数已经被lock时,该函数会令当前thread wait直到locker可以被lock。
/* mutex locks to avoid race conditions */
#include "./header.h"
pthread_mutex_t locker;
// pthread_mutex_init(&locker, NULL);
// pthread_mutex_lock(&locker);
// pthread_mutex_trylock(&locker);
// pthread_mutex_unlock(&locker);
// pthread_mutex_unlock(&locker);
// pthread_mutex_destroy(&locker);
int x=0;
void *threaded_routine (void * v) {
const int *n = (int *)v;
int i;
for (i=0; i<10; i++) {
pthread_mutex_lock(&locker);
int y=x;
y++;
printf("%d: y=%d\n",*n,y);
sleep(1);
x=y;
printf("%d: x=%d\n",*n,x);
pthread_mutex_unlock(&locker);
}
}
main()
{
pthread_t thread1, thread2, thread3;
void *retptr;
int n1=1,n2=2,n3=3;
pthread_mutex_init(&locker, NULL);
pthread_create( &thread1, NULL, threaded_routine, (void *)&n1);
pthread_create( &thread2, NULL, threaded_routine, (void *)&n2);
pthread_create( &thread3, NULL, threaded_routine, (void *)&n3);
printf("joining thread 1\n");
pthread_join(thread1,(void **)&retptr);
printf("joining thread 2\n");
pthread_join(thread2,(void **)&retptr);
printf("joining thread 3\n");
pthread_join(thread3,(void **)&retptr);
printf ("x = %d (should be 30)\n",x);
pthread_mutex_destroy(&locker);
}