美文网首页
Head First C学习之使用线程

Head First C学习之使用线程

作者: 如野随风 | 来源:发表于2016-04-14 16:44 被阅读37次
  • 创建进程程的效率低,
  • 进程共享数据不方便
  • 进程的代码比较冗余

因此有时需要线程

如何创建线程

使用流行的线程库:POSIX线程库,也叫pthread。
假设独立线程运行两个函数

void* does_not(void *a)
{
    for(int i = 0;i < 5; i++){
    sleep(1);
    puts("Does not")
    }
    return NULL;
}

void* does_too(void*a)
{   
    for(int i = 0;i < 5; i++){
    sleep(1);
    puts("Does too")
    }
    return NULL;
}

void指针是可以指向存储器中任何类型的数据。

使用pthread_create创建线程

头文件和函数声明

#include<pthread.h>
...
int pthread_create(pthread_t *tidp,
const pthread_attr_t *attr,
(void*)(*start_rtn)(void*),
void *arg);
  • 第一个参数为指向线程标识符的指针。
  • 第二个参数用来设置线程属性。
  • 第三个参数是线程运行函数的起始地址。
  • 最后一个参数是运行函数的参数。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>//pthread库的头文件

void error(char *msg)
{
    fprintf(stderr,"%s:%s\n",msg.strerror(errno));
    exit(1);
}

每个线程都需要把信息保存在一个叫pthread_t的数据结构中,然后用pthread_create()创建并运行线程。

pthread_t t0;
pthread_t t1;
if(prhread_greate(&t0,NULL,does_not,NULL) == -1)
    error("无法创建线程t0");
if(prhread_greate(&t1,NULL,does_too,NULL) == -1)
    error("无法创建线程t1");

代码将以独立线程运行这两个函数,程序运行完这段代码,线程也会随之灭亡,因此必须等待线程结束。

void* result;
//函数返回的void指针回保存在这里
if(pthread_join(t0,&result) == -1)
    error("无法回收线程t0");
if(pthread_join(t1,&result) == -1)
    error("无法回收线程t1");

pthread_join()会接收线程函数的返回值,并把它保存在void指针变量中,一旦线程都结束,程序就可以顺利退出。

互斥锁

线程之间共享数据,因此需要互斥锁,来保护某段代码的安全。

pthread_mutex_t a_lock = PTHREAD_MUTEX_INITIALIZER;

互斥锁必须对所有有可能发生冲突的线程可见,也就是说它是一个全局变量
PTHREAD_MUTEX_INITIALIZER是一个宏,当编译器看到它,就会插入创建互斥锁的代码。

1、红灯停

pthread_mutex_lock(&a_lock);
//一次只允许一个线程通过这里.
//其他线程运行到这里必须等待
/*含有共享数据的代码从这里开始*/

2、绿灯行

/*含有共享数据的代码结束*/
pthread_mutex_umlock(&a_local);

void指针参数

线程函数可以接受一个void指针作参数并返回一个void指针值,因为long的大小和void指针大小相同,可以把它保存在void指针变量中

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>//pthread库的头文件

void error(char *msg)
{
    fprintf(stderr,"%s:%s\n",msg,strerror(errno));
    exit(1);
}
//线程函数接收一个void指针类型的参数
void* do_stuff(void* param)
{
    long thread_no = (long)param;//把它强子转化long
    printf("Thread number %ld\n",thread_no);
    return(void*)(thread_no + 1);
}

int main()
{
    pthread_t threads[3];
    long t;
    for(t = 0; t < 3; t++ ){
        if(pthread_create(&threads[t],NULL,do_stuff,(void*)t) == -1)
            error("创建线程是失败");
        //将long型指针变量t转化为void指针
    }
    void* result;
    for(t = 0; t < 3;t++){
        if(pthread_join(threads[t],&result) == -1)
            error("无法回收线程");
        printf("Thread %ld return %ld\n",t,(long)result);
    }
    return 0;
}

运行:

#./param_test
Thread number 0
Thread number 1
Thread number 2
Thread 0 return 1
Thread 1 return 2
Thread 2 return 3

练习代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>//pthread库的头文件

int beers = 2000000;
pthread_mutex_t beers_lock = PTHREAD_MUTEX_INITIALIZER;

void error(char *msg)
{
    fprintf(stderr,"%s:%s\n",msg,strerror(errno));
    exit(1);
}
//线程函数接收一个void指针类型的参数
void* drink_lots(void* a)
{
    int i;
    pthread_mutex_lock(&beers_lock);
    for(i = 0; i < 100000; i++)
        beers = beers - 1;
    pthread_mutex_unlock(&beers_lock);
    printf("beers = %i\n", beers);
    return NULL;
}

int main()
{
    pthread_t threads[20];
    int t;
    printf("%i bottles of bear on the wall\n%i bottles of beer\n",beers,beers );
    for(t = 0; t < 20; t++ ){
        if(pthread_create(&threads[t],NULL,drink_lots,NULL) == -1)
            error("创建线程失败");
    }
    void* result;
    for(t = 0; t < 20;t++){
        if(pthread_join(threads[t],&result) == -1)
            error("回收线程失败");

    }
    printf("There are now %i bottles of beer on the wall\n", beers);
    return 0;
}

版本2:

...
void* drink_lots(void* a)
{
    int i;
        for(i = 0; i < 100000; i++){
            pthread_mutex_lock(&beers_lock);
            beers = beers - 1;
            pthread_mutex_unlock(&beers_lock);
        }
    printf("beers = %i\n", beers);
    return NULL;
}
...
  • 线程会让程序变得更快,但要孔子代码中锁的数量,如果锁太多,就会像单线程一样慢。
  • 创建进程要比创建线程花更多的时间。
  • 互斥锁会引发『死锁』

相关文章

网友评论

      本文标题:Head First C学习之使用线程

      本文链接:https://www.haomeiwen.com/subject/seiglttx.html