初试Linux下的线程编程

如何创建线程

Linux下一般使用POSIX线程库,也叫pthread。编写线程函数需要注意的是线程函数的返回类型必须是void*;程序编译的时候记得要链接上pthread库,方法:-lpthread

简单的线程程序

下面是简单的线程程序,主程序里创建了2个线程,分别打印不同的信息。每个线程用pthread_create函数来创建。每个线程运行完程序之后,必须使用pthread_join函数来等待线程结束,也就是回收线程。一旦两个线程都退出后,主程序就会退出。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

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

void* hello(void *a)
{
    int i = 0;
    for(i = 0; i < 5; i++)
    {
        sleep(1);
        puts("hello linux!");
    }

    return NULL;
}

void* goodbye(void *a)
{
    int i = 0;
    for(i = 0; i < 5; i++)
    {
        sleep(1);
        puts("goodbye linux!");
    }

    return NULL;
}

int main(int argc, char const *argv[])
{
    pthread_t t0;
    pthread_t t1;

    if(pthread_create(&t0, NULL, hello, NULL) == -1)
        error("cant creat pthread t0");
    if(pthread_create(&t1,NULL, goodbye, NULL) == -1)
        error("cant creat pthread t1");

    void* result;
    if(pthread_join(t0, &result) == -1)
        error("cant join pthread t0");
    if(pthread_join(t1, &result) == -1)
        error("cant join pthread t1");
    return 0;
}

如果编译程序没有添加-lpthread,就会出现下面的错误

root@zengwh:~/test_code# gcc -Wall pthread.c -o pthread
/tmp/cc5KEYbr.o:在函数‘main’中:
pthread.c:(.text+0xec):对‘pthread_create’未定义的引用
pthread.c:(.text+0x116):对‘pthread_create’未定义的引用
pthread.c:(.text+0x138):对‘pthread_join’未定义的引用
pthread.c:(.text+0x15a):对‘pthread_join’未定义的引用
collect2: error: ld returned 1 exit status

成功编译后,结果如下:

root@zengwh:~/test_code# gcc -Wall pthread.c -lpthread -o pthread
root@zengwh:~/test_code# ./pthread 
goodbye linux!
hello linux!
goodbye linux!
hello linux!
goodbye linux!
hello linux!
hello linux!
goodbye linux!
hello linux!
goodbye linux!

多个线程访问共享数据

下面的程序,同时创建10个线程,每个线程公用一个函数,都是将全局变量number 减1000,等所有线程结束之后,再打印出变量的值,看是否等于0.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

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

void* func(void *a)
{
    int i = 0;
    for (i = 0; i < 1000; ++i)
    {
        number -= 1;
    }

    return NULL;
}



int main(int argc, char const *argv[])
{
    pthread_t thread[10];

    int j = 0;

    printf("begining: the number is : %d\n", number );
    for (j = 0; j < 10; ++j)
    {
        if (pthread_create(&thread[j], NULL, func, NULL) == -1)
            error("cant creat pthread t0");
    }

    void* result;

    for (j = 0; j < 10; ++j)
    {
        if (pthread_join(thread[j], &result) == -1)
            error("cant creat pthread t0");
    }
    printf("finally: the number is : %d\n", number );
    return 0;
}

程序运行结果如下:

root@zengwh:~/test_code# ./pthread 
begining: the number is : 10000
finally: the number is : 882
root@zengwh:~/test_code# ./pthread 
begining: the number is : 10000
finally: the number is : 801
root@zengwh:~/test_code# ./pthread 
begining: the number is : 10000
finally: the number is : 501
root@zengwh:~/test_code# ./pthread 
begining: the number is : 10000
finally: the number is : 634
root@zengwh:~/test_code# ./pthread 
begining: the number is : 10000
finally: the number is : 887

每次运行的结果都不一样。线程最大的优点在于可以同时运行多个不同任务,并访问相同的数据,但访问相同的数据也成为了线程的缺点。上面程序的结果就是线程撞车,结果是不可预测的。

创建互斥锁

为了让多个线程可以访问共享数据且不会发生撞车,一种简单办法就是创建互斥锁。

pthread_mutex_t a_lock = PTHREAD_MUTEX_INITIALIZER;

互斥锁必须是一个全局变量,这样才能对所有有可能发生撞车的线程可见。pthread_mutex_lock()函数只允许一个线程运行,其他线程处于等待。然后调用pthread_mutex_unlock()函数解锁,其他线程可以进入。

pthread_mutex_lock(&a_lock);
/*需要访问的共享数据*/
pthread_mutex_unlock(&a_lock);

增加锁后的程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

int number = 10000;

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

void* func(void *a)
{
    int i = 0;

    pthread_mutex_lock(&number_lock);
    for (i = 0; i < 1000; ++i)
    {
        number -= 1;
    }
    pthread_mutex_unlock(&number_lock);
    printf("the number is : %d\n", number );
    return NULL;
}



int main(int argc, char const *argv[])
{
    pthread_t thread[10];

    int j = 0;

    printf("begining: the number is : %d\n", number );
    for (j = 0; j < 10; ++j)
    {
        if (pthread_create(&thread[j], NULL, func, NULL) == -1)
            error("cant creat pthread t0");
    }

    void* result;

    for (j = 0; j < 10; ++j)
    {
        if (pthread_join(thread[j], &result) == -1)
            error("cant creat pthread t0");
    }
    printf("finally: the number is : %d\n", number );
    return 0;
}

需要注意的是

  • 要控制代码中锁的数量,不然会使程序变得很慢;
  • 减少线程需要访问的共享数据的数量,程序会更高效地进行

你可能感兴趣的:(线程,pthread)