Chapter 1: Getting started with pthreads
Examples
1 最小 "Hello World" with pthreads
2 传参 到 threads
3 从 thread 返回 结果
Chapter 2: Conditional Variables
介绍
注意
Examples
1 Producer / Consumer
Chapter 3: Race condition in pthreads
介绍
Examples
1 Consider will have two threads T1 and T2
// ===
Chapter 1: Getting started(开始) with pthreads
Examples
1 最小 "Hello World" with pthreads
// hello.c
/* compile: $ gcc -pthread -o hello hello.c */
#include <pthread.h>
#include <stdio.h>
#include <string.h>
/* thread function must have the same signature:
[1] para : void*
[2] returns : void*
*/
void *threadFunction(void *arg)
{
printf("Hello, World!\n"); /* printf(): thread-safe as of C11 */
return 0;
}
int main(void)
{
pthread_t thread;
/* creates new thread:
1] default attributes
2] NULL passed as the argument to start routine
*/
int createerror = pthread_create(&thread, NULL, threadFunction, NULL);
if (!createerror) /* 0: success */
{
pthread_join(thread, NULL); /* wait until the created thread terminates */
return 0;
}
/* stderr: [1] error info output to screen, whether or not relocate( hello > error.txt)
char *strerror(int errnum)
[1] searches internal array for the error number errnum
[2] returns a pointer to it's error message string
*/
fprintf(stderr, "%s\n", strerror(createerror) );
return 1;
}
$ gcc -pthread -o a hello.c
& ./a
// print
hello
2 传参 到 threads
// passArgsToThread.c
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
printf("I am thread #%d\n", *(int *)arg);
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t t1, t2;
int i = 1;
int j = 2;
/* 2 threads execute function "thread_func()" in their own contexts */
pthread_create(&t1, NULL, &thread_func, &i);
pthread_create(&t2, NULL, &thread_func, &j);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("In main thread\n");
return 0;
}
$ gcc -pthread -o a passArgsToThread.c
& ./a
// print
I am thread #1
I am thread #2
In main thread
3 从 thread 返回 结果
A ptr to concrete data type, 被转换 为 void *, 可用于
1] 传递值到 thread functon
2] 从 thread function 返回结果
(1) thread 内 malloc, return heap memory's ptr, join 中 取
(2) argument struct 中 space 也可 用于 return results
(3) ptr to shared data 可被 传给线程, results stored there
// returnResultFromThread.c
// way1
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
struct thread_args
{
int a;
double b;
};
struct thread_result
{
long x;
double y;
};
void *thread_func(void *args_void)
{
// (2) para: void* -> ptr, 不用显式强转
struct thread_args *args = args_void;
/* (3) Note1: thread 不能 return ptr to it's local variable */
struct thread_result *res = malloc(sizeof *res);
res->x = 10 + args->a;
res->y = args->a * args->b;
return res;
}
int main()
{
pthread_t thread;
struct thread_args in = { .a = 10, .b = 3.141592653 };
void *out_void;
struct thread_result *out;
// (1) arg: ptr -> void*
pthread_create(&thread, NULL, thread_func, &in);
// (4) Note2: result: void* 的 地址 放 join
pthread_join(thread, &out_void);
// (5) result: void* -> ptr
out = out_void;
printf("out -> x = %ld\tout -> b = %f\n", out->x, out->y);
// (6) free memory malloced within thread
free(out);
return 0;
}
$ gcc -pthread -o a returnResultFromThread.c
$ ./a
out -> x = 20 out -> b = 31.415927
Chapter 2: Conditional Variables
介绍
cv 适用场景: 希望 a thread 等待 another thread 中 发生某事
生产者(>=1) /消费者(=1) 模型
cv 可用于 signal(向...发出信号) 消费者线程 new data is available(新数据可用)
注意
通常过程
wait on cv 总是
与 mutex 耦合
与 "正常" state variable 耦合( queue.empty() )
对 signalling thread
1 Lock mutex // ===
2 Update any data and state variables
3 Signal cv
4 Unlock mutex // ===
对 waiting thread
1 Lock mutex // ===
2 while loop on state variable, when data is not ready
3 within while loop, wait on cv // ===
// Note: cv.wait call
// unlocks mutex when called,
// relocks it before returning!
4 Do something with the data
5 Unlock the mutex and repeat // ===
Examples
1 Producer / Consumer
// cv.c
/*
lock: 保护 queue 上 并发操作 的 正确
lock 保护范围
对 生成者: push()
对 消费值: front() + pop()
lock 不保护的范围
对 生成者: 准备好 要 push 到 queue 的 data 前
对 消费值: 从 queue 取出/front() + 删除/pop() data 后 的 数据处理
*/
pthread_mutex_t queueMutex;
pthread_cond_t queueEmptyCv;
Queue queue;
void Initialize()
{
//Initialize the mutex and the condition variable
pthread_mutex_init(&queueMutex, NULL);
pthread_cond_init(&queueEmptyCv, NULL);
}
void Producer()
{
// Note: get new data, 不必 within lock
Data *newData = MakeNewData(); // (0)
// Lock queue mutex: make sure that adding data to queue happens correctly
pthread_mutex_lock(&queueMutex); // === lock
// Push new data to queue
queue.push(newData); // (1) push
// Signal cv that new data is available in the queue
pthread_cond_signal(&queueEmptyCv); // (2) signal
// Done, unlock the mutex
pthread_mutex_unlock(&queueMutex); // === unlock
}
void Consumer()
{
//Run the consumer loop
while(1)
{
pthread_mutex_lock(&queueMutex); // ===
while( queue.empty() )
{
// - wait for cv to be signalled
// Note: cv.wait call
// unlocks mutex when called,
// relocks it before returning!
pthread_cond_wait(&queueEmptyCv, &queueMutex); // === (1) cv.wait
}
// now, there must be new data in the queue - get it,
Data *newData = queue.front(); // (2)
// remove it from the queue
queue.pop(); // (3)
// unlock the mutex
pthread_mutex_unlock(&queueMutex); // ===
// process the new data
ProcessData(newData); // (4)
}
}
Chapter 3: Race condition in pthreads
介绍
Note: 若 所有线程 只是 read variable/resource/memory 位置(location),
Race Condition 不会发生
Examples
1 Consider will have two threads T1 and T2
// raceConditionProblem.c
#include <stdio.h>
#include <pthread.h>
int x= 0; // shared data(variable)
void* fun(void* in)
{
int i;
for ( i = 0; i < 10000000; i++ )
x++;
}
int main()
{
pthread_t t1, t2;
printf("Point 1 >> X is: %d\n", x);
pthread_create(&t1, NULL, fun, NULL);
pthread_create(&t2, NULL, fun, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("Point 2 >> X is: %d\n", x);
return 0;
}
// raceConditionSolved.c
#include <stdio.h>
#include <pthread.h>
int x= 0;
pthread_mutex_t test_mutex; // Create mutex: shared mutex
void* fun(void* in)
{
int i;
for ( i = 0; i < 10000000; i++ )
{
pthread_mutex_lock(&test_mutex); // === lock
x++;
pthread_mutex_unlock(&test_mutex); // === unlock
}
}
int main()
{
pthread_t t1, t2;
printf("Point 1 >> X is: %d\n", x);
//Initlize mutex
pthread_mutex_init(&test_mutex, NULL); // === init
pthread_create(&t1, NULL, fun, NULL);
pthread_create(&t2, NULL, fun, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
//Destroy mutex after use
pthread_mutex_destroy(&test_mutex); // === destroy
printf("Point 2 >> X is: %d\n", x);
return 0;
}
// print
Point 1 >> X is: 0
Point 2 >> X is: 20000000
网友评论