os线程实验

本文详细介绍了在C语言中使用pthread库进行多线程编程的方法,包括线程创建、线程同步(互斥量、条件变量)以及线程间的通信。通过实例展示了如何解决并发修改导致的输出不一致问题,并演示了使用条件变量实现的生产者消费者模型。此外,还讨论了线程的返回值处理和资源管理策略。
摘要由CSDN通过智能技术生成

创建线程

原型

#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 = &params[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;
}

结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值