POSIX线程

1.概念


线程:在一个程序中的多个执行路线就叫做线程,更准确的定义:线程是一个进程内部的一个控制序列。

线程的优点:让程序并行执行;改善程序性能;线程的切换需要操作系统做的工作较少,因此多个线程对资源的需要远小于多个进程。

线程的缺点:多线程程序设计复杂;多线程程序高度难度较大;对于大量计算且在单核计算机线程运行的效率不高。

编写多线程程序需要包含头文件pthread.h,并且在编译程序时需要用选项-lpthread链接线程库。除此之外还需要定义宏_REENTRANT告诉编译器程序需要可重入功能。

可重入:可以被多次调用而仍然正常工作。

编译和链接:gcc -D_REENTRANT -I/usr/include/nptl -o xxx xxx.c -L/usr/lib/nptl -lpthread

 若系统默认使用了上诉的库,可以直接:gcc  -o xxx xxx.c  -lpthread


2.创建一个新进程

#include<pthread.h>

int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

第一个参数时指向 pthread_t 类型数据的指针,线程被创建时,这个指针指向的变量中将被写入一个标识符,我们用该标识符来引用新线程。

下一个参数用于设置线程的属性,一般设置NULL。第三个参数传递一个函数的地址,最后一个参数是传递给该函数的参数。

函数调用成功返回0,失败返回错误代码。


3.终止线程

#include<pthread.h>

int pthread_exit(void *retval);

终止调用它的线程并返回一个指向某个对象的指针。

4.join

#include<pthread>

int pthread_join(pthread_t th, void **thread_return);
等价于进程中用来收集子进程信息的wait函数。第一个参数是上面提到的标识符,第二个参数是指向另一个指针的指针,另一个指针指向线程的返回值。


5.同时执行

除局部变量外,所有其他变量都将在一个进程中的所有线程之间共享


6.同步

更好的控制线程执行和访问代码临界区域的方法:

a.信号量:分为二进制信号量(保护一段代码使其只能被一个执行线程运行)和计数信号量(允许有限数目的线程执行一段指定的代码)。

b.创建信号量

#include<semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);
函数初始化由sem指向的信号量对象,设置它的共享选项,并给他一个初始值value(一般为0),第二个参数控制信号量类型(0表示局部信号量,否则可以表示共享)。

c.控制信号量

#include<semaphore.h>

int sem_wait(sem_t * sem);//给信号量值减一

int sem_post(sem_t * sem);//给信号量值加一

//都是原子操作(无冲突)

d.信号量清理

#include<semaphore.h>

int sem_destroy(sem_t * sem);

清理该信号量所有资源

7.用互斥量进行同步

互斥量允许程序锁住某个对象,使得每次只能有一个线程访问它。为了控制关键代码的访问,必须在进入代码段之前锁住一个互斥量,然后在完成操作后解锁。


#include<pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//上述函数调用执行成功时返回0,失败时返回错误代码,但是不设置errno

 


#include <pthread.h>

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

void *thread_function(void *arg);
pthread_mutex_t work_mutex; /* protects both work_area and time_to_exit */

#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int time_to_exit = 0;
int time_to_exit = 0;

int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    res = pthread_mutex_init(&work_mutex, NULL);
    if (res != 0) {
        perror("Mutex initialization failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_create(&a_thread, NULL, thread_function, NULL);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    pthread_mutex_lock(&work_mutex);
    printf("Input some text. Enter 'end' to finish\n");
    while(!time_to_exit) {
        fgets(work_area, WORK_SIZE, stdin);
        pthread_mutex_unlock(&work_mutex);
        while(1) {
            pthread_mutex_lock(&work_mutex);
            if (work_area[0] != '\0') {
                pthread_mutex_unlock(&work_mutex);
                sleep(1);
            }
            else {
                break;
            }
        }
    }
    pthread_mutex_unlock(&work_mutex);
    printf("\nWaiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined\n");
    pthread_mutex_destroy(&work_mutex);
    exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
    sleep(1);
    pthread_mutex_lock(&work_mutex);
    while(strncmp("end", work_area, 3) != 0) {
        printf("You input %d characters\n", strlen(work_area) -1);
        work_area[0] = '\0';
        pthread_mutex_unlock(&work_mutex);
        sleep(1);
        pthread_mutex_lock(&work_mutex);
        while (work_area[0] == '\0' ) {
            pthread_mutex_unlock(&work_mutex);
            sleep(1);
            pthread_mutex_lock(&work_mutex);
        }
    }
    time_to_exit = 1;
    work_area[0] = '\0';
    pthread_mutex_unlock(&work_mutex);
    pthread_exit(0);
}          

8. 线程的属性

在创建线程之前可以通过设置线程的发生改变所创建线程的行为。线程有很多属性可以设置,比如可取消的状态、可取消类型、并发度,通过改变这些属性可以更精确地控制线程的运行。


#include<pthread.h>

int pthread_attr_init(pthread_attr_t *attr);

初始化一个线程属性对象。还有一个pthread_attr_destroy 是对属性对象进行清理和回收。

9.取消线程

一个线程可以要求另一个线程终止,可能通过pthread_cancel实现。接收到终止消息的线程可以调用pthread_setcancelstate设置自己的取消状态。如果取消请求被接受,线程可以调用pthread_setcanceltype设置取消类型。取消类型有两种,PTHREAD_CANCEL_ASYNCHRONOUS使得在接收到取消请求后立即采取行动,PTHREAD_CANCEL_DEFERRED使得在接收到取消请求后,一直等待直到线程执行了pthread_join、pthread_cond_wait、pthread_cond_timewait、pthread_testcancel、sem_wait、sigwait中的任意一个函数后才采取行动。

#include <pthread.h>
int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);//设置取消状态
int pthread_setcanceltype(int type, int *oldtype);//设置取消类型


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值