创建线程
原型
#include<pthread.h>
int pthread_create(pthread_t *tid, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
功能
创建一个新线程
新线程从start_routine开始执行
新线程的ID保存在tid指向的位置
void *(*start_routine)(void * args)
参数
参数 | 功能 |
tid | 该参数是一个指针, 新线程的ID保存在tid指向的位置 |
attr | 线程属性。如果为空,则使用缺省的属性值 |
start_routine | 该参数是一个函数指针, 新线程从start_routine开始执行 |
arg | 提供给start_routine的参数 |
arg参数的类型
可以向线程入口函数传递任意类型的参数
整型变量
int ivalue = 123;
void *arg = (void *) ivalue;
pthread_create(&tid, NULL, start_routine, arg);
字符串变量
char *svalue = "string";
void *arg = (void *) svalue;
pthread_create(&tid, NULL, start_routine, arg);
结构体变量,只能传递结构体的地址
struct person {
char *name;
int age;
} p;
void *arg = (void *) &p;
pthread_create(&tid, NULL, start_routine, arg);
返回值
如果成功,返回0
如果失败,返回非0
列子1
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void *compute(void *arg)
{
char i;
for( i = 'a' ; i < 'd' ; i++)
{
printf("worker :%c\n",i);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t worker_tid;
pthread_create(&worker_tid,NULL,&compute,NULL);
char i;
for( i = 'A' ; i < 'D' ; i++)
{
printf("master :%c\n",i);
sleep(1);
}
return NULL;
}
在编译器执行的过程中
会找不到库pthread_create
此时在编译后加入一个 -lpthread
列子2
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
void *compute(void *arg)
{
char *string = arg;
int i;
for (i = 0; i < 3; i++) {
puts(string);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t worker_tid;
pthread_create(&worker_tid, NULL, &compute, "worker");
compute("master");
return 0;
}
等待线程
原型
#include <pthread.h>
int pthread_join(pthread_t tid, void **result);
功能
等待线程结束
参数
tid | 目标线程的ID |
result | 用于存放线程的计算结果 |
返回值
如果成功,返回0
如果失败,返回非0
列子1
#include <stdio.h>
#include <pthread.h>
int array[] = {1, 1, 1, 2, 2, 2};
#define NUMBER 6
int worker_output;
void *worker(void *arg)
{
int i;
for (i = 0; i < NUMBER / 2; i++)
worker_output += array[i];
return NULL;
}
int master_output;
void master()
{
int i;
for (i = NUMBER / 2; i < NUMBER; i++)
master_output += array[i];
}
int main()
{
pthread_t worker_tid;
int total;
pthread_create(&worker_tid, NULL, worker, NULL);
master();
pthread_join(worker_tid, NULL); //等待工作线程工作完毕
total = master_output + worker_output;
printf("master_output = %d, worker_output = %d, total = %d\n", master_output, worker_output, total);
return 0;
}
存在的问题
代码重复
不能够普遍化
线程返回值
线程入口函数返回类型为void **类型的结果
void *start_routine(void *arg)
{
void *result;
...
return result;
}
等待线程函数pthread_join获取线程的返回结果
void *result;
pthread_join(tid, &result);
对其进行改善
一共有1+NR_CPU 个线程,其中主线程是将每个子线程的结果加起来
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
int array[] = {1, 1, 1, 2, 2, 2};
#define NR_TOTAL 6
#define NR_CPU 2 //子线程数
#define NR_CHILD (NR_TOTAL/NR_CPU) //每个子线程需要处理资源的个数
struct param {
int *array;
int start;
int end;
};
struct result {
int sum;
};
void *compute(void *arg)
{
struct param *param;
struct result *result;
int sum = 0;
int i;
param = (struct param *)arg;
for (i = param->start; i < param->end; i++)
sum += param->array[i];
result = malloc(sizeof(struct result));
result->sum = sum;
return result;
}
int main()
{
pthread_t workers[NR_CPU];
struct param params[NR_CPU];
int i;
for (i = 0; i < NR_CPU; i++) {
struct param *param;
param = ¶ms[i];
param->array = array;
param->start = i * NR_CHILD;
param->end = (i + 1) * NR_CHILD;
pthread_create(&workers[i], NULL, compute, param);
}
int sum = 0;
for (i = 0; i < NR_CPU; i++) {
struct result *result;
pthread_join(workers[i], (void **)&result);
sum += result->sum;
free(result);
}
printf("sum = %d\n", sum);
return 0;
}
线程互斥
初始化互斥量
原型
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
attr为NULL,则使用缺省的属性进行初始化。
成功返回0,失败返回非0;
加锁解锁
原型
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
成功返回0,失败返回非0;
列子
若不使用互斥量
#include <stdio.h>
#include <pthread.h>
volatile int global = 0;
void *compute(void *arg)
{
int i;
for (i = 0; i < 100 * 100 * 100; i++) {
global++;
}
return NULL;
}
int main()
{
int i;
pthread_t tids[3];
global = 0;
for (i = 0; i < 3; i++)
pthread_create(&tids[i], NULL, compute, NULL);
for (i = 0; i < 3; i++)
pthread_join(tids[i], NULL);
printf("global = %d\n", global);
return 0;
}
其结果应该为300000
但其结果却是
并且每一次都不一样,这是由于并发修改造成程序的输出结果与预期不一致;
使用互斥量后:
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex;
volatile int global = 0;
void *compute(void *arg)
{
int i;
for (i = 0; i < 100 * 100 * 100; i++) {
pthread_mutex_lock(&mutex);
global++;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
int i;
pthread_t tids[3];
pthread_mutex_init(&mutex, NULL);
for (i = 0; i < 3; i++)
pthread_create(&tids[i], NULL, compute, NULL);
for (i = 0; i < 3; i++)
pthread_join(tids[i], NULL);
pthread_mutex_destroy(&mutex);
printf("global = %d\n", global);
return 0;
}
得到其结果为3000000
条件变量
初始化
原型
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
功能
pthread_cond_init初始化条件变量
pthread_cond_destroy释放条件变量
参数
如果attr等于NULL,则使用缺省的属性进行初始化
返回值
如果成功,返回0
如果失败,返回非0
等待
原型
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
功能
阻塞当前线程的运行
参数
cond | 当前线程在条件变量上阻塞 |
mutex | 当前线程阻塞时所在的临界区 |
返回值
如果成功,返回0
如果失败,返回非0
唤醒线程
原型
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
功能
pthread_cond_signal唤醒阻塞在条件变量上的一个线程
pthread_cond_broadcast唤醒阻塞在条件变量上的所有线程
返回值
如果成功,返回0
如果失败,返回非0
例子
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#define CAPACITY 4
int buffer[CAPACITY];
int in;
int out;
int buffer_is_empty()
{
return in == out;
}
int buffer_is_full()
{
return (in + 1) % CAPACITY == out;
}
int get_item()
{
int item;
item = buffer[out];
out = (out + 1) % CAPACITY;
return item;
}
void put_item(int item)
{
buffer[in] = item;
in = (in + 1) % CAPACITY;
}
typedef struct {
int value;
pthread_mutex_t mutex;
pthread_cond_t cond;
} sema_t;
void sema_init(sema_t *sema, int value)
{
sema->value = value;
pthread_mutex_init(&sema->mutex, NULL);
pthread_cond_init(&sema->cond, NULL);
}
void sema_wait(sema_t *sema)
{
pthread_mutex_lock(&sema->mutex);
while (sema->value <= 0)
pthread_cond_wait(&sema->cond, &sema->mutex);
sema->value--;
pthread_mutex_unlock(&sema->mutex);
}
void sema_signal(sema_t *sema)
{
pthread_mutex_lock(&sema->mutex);
++sema->value;
pthread_cond_signal(&sema->cond);
pthread_mutex_unlock(&sema->mutex);
}
sema_t mutex_sema;
sema_t empty_buffer_sema;
sema_t full_buffer_sema;
#define ITEM_COUNT (CAPACITY * 2)
void *consume(void *arg)
{
int i;
int item;
for (i = 0; i < ITEM_COUNT; i++) {
sema_wait(&full_buffer_sema);
sema_wait(&mutex_sema);
item = get_item();
printf(" consume item: %c\n", item);
sema_signal(&mutex_sema);
sema_signal(&empty_buffer_sema);
}
return NULL;
}
void *produce()
{
int i;
int item;
for (i = 0; i < ITEM_COUNT; i++) {
sema_wait(&empty_buffer_sema);
sema_wait(&mutex_sema);
item = i + 'a';
put_item(item);
printf("produce item: %c\n", item);
sema_signal(&mutex_sema);
sema_signal(&full_buffer_sema);
}
return NULL;
}
int main()
{
pthread_t consumer_tid;
sema_init(&mutex_sema, 1);
sema_init(&empty_buffer_sema, CAPACITY - 1);
sema_init(&full_buffer_sema, 0);
pthread_create(&consumer_tid, NULL, consume, NULL);
produce();
pthread_join(consumer_tid, NULL);
return 0;
}
结果