Linux线程02

学习内容

线程的取消
线程和信号,与多进程的信号有不同
线程安全,一切麻烦从共享资源开始
线程同步,各种锁的使用

线程取消

int pthread_cancel(pthread_t thread);

线程取消
线程取消点

// 本程序演示线程的取消。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

int var=0;

void *thmain(void *arg);    // 线程主函数。

int main(int argc,char *argv[])
{
  pthread_t thid;

  // 创建线程。
  if (pthread_create(&thid,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }

  usleep(100); pthread_cancel(thid);

  int result=0;
  void *ret;
  printf("join...\n");
  result=pthread_join(thid,&ret);   printf("thid result=%d,ret=%ld\n",result,ret);
  printf("join ok.\n");

  printf("var=%d\n",var);
}

void *thmain(void *arg)    // 线程主函数。
{
  // pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);

  for (var=0;var<400000000;var++)
  {
    ;
    pthread_testcancel();
  }
  return (void *) 1;
}

线程和信号

进程和信号 and 线程和信号的区别:
线程和信号
线程和信号2

线程安全

什么是可重入函数?
可重入的函数简单来说就是可以被中断的函数
一文理解可重入函数

什么是原子性?

什么是可见性?
可见性
什么是顺序性?
顺序性
volatile关键字?

volatile不是原子的。

如何解决线程安全?

解决线程安全

原子操作只支持整数。支持对象要用线程同步

线程同步,各种锁的使用

互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

互斥锁的demo:

#include <pthread.h>


pthread_mutex_t mutex;
int max = 0;
void* arg_main1(void* arg) {
    for(int i = 0;i < 100; i++) {
        pthread_mutex_init(&mutex,NULL);
        max += 1;
        printf("arg_main1 max = %d \n",max);
        //sleep(1);
        pthread_mutex_unlock(&mutex);
    } 
}
void* arg_main2(void* arg) {
    
    for(int i = 0;i < 100; i++) {
        pthread_mutex_init(&mutex,NULL);
        max += 1;
        printf("arg_main2 max = %d \n",max);
        //sleep(1);
        pthread_mutex_unlock(&mutex);
    } 
}

int main()
{
    
    pthread_mutex_init(&mutex,NULL);

    pthread_t pid1,pid2;
    pthread_create(&pid1,NULL,&arg_main1,NULL);
    pthread_create(&pid2,NULL,&arg_main2,NULL);

    pthread_join(pid1,NULL);
    pthread_join(pid2,NULL);
    printf("max = %d \n",max);

    pthread_mutex_destroy(&mutex);
    return 0;
}
锁的属性

锁的属性
锁的属性
锁的属性

互斥锁和自旋锁的区别?

互斥锁不消耗cpu,线程会休眠,而自旋锁会消耗cpu,它用cpu使用
使用自旋锁假设等待时间很短。
等待时间短使用自旋锁,等待时间长使用互斥锁。
pthread_mutex_init和pthread_spin_init 第二个参数不同,mutex是属性,spin是一个标志。
加锁解锁时候也不同:一个要两个参数,一个要一个参数。

自旋锁

api如下:

int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
PTHREAD_PROCESS_PRIVATE 能否共享自旋锁? 一般填私有的。
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);

自旋锁使用demo:

#include <pthread.h>

pthread_spinlock_t mutex;// 定义自旋锁

int max = 0;
void* arg_main1(void* arg) {
    for(int i = 0;i < 100; i++) {
        pthread_spin_lock(&mutex);
        max += 1;
        printf("arg_main1 max = %d \n",max);
        usleep(1);
        pthread_spin_unlock(&mutex);
    } 
}
void* arg_main2(void* arg) {
    
    for(int i = 0;i < 100; i++) {
        pthread_spin_lock(&mutex);
        max += 1;
        printf("arg_main2 max = %d \n",max);
        usleep(2);
        pthread_spin_unlock(&mutex);
    } 
}

int main()
{
    
    pthread_spin_init(&mutex,PTHREAD_PROCESS_PRIVATE);

    pthread_t pid1,pid2;
    pthread_create(&pid1,NULL,&arg_main1,NULL);
    pthread_create(&pid2,NULL,&arg_main2,NULL);

    pthread_join(pid1,NULL);
    pthread_join(pid2,NULL);
    printf("max = %d \n",max);

    pthread_spin_destroy(&mutex);
    return 0;
}

读写锁

api:

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock);// 读锁
int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock);// 写锁
int pthread_rwlock_unlock(pthread_rwlock_t *__rwlock);// 解锁
  1. 读写锁支持高并发
  2. 读写锁有三种状态:读模式加锁,写模式加锁和不加锁。
    读写锁
读写锁的特点

读写锁的特点

读写锁注意点

读写锁注意点

读写锁和互斥锁的区别?
  1. 读写锁有三种状态。互斥锁只有两种。
    读写锁demo:
// 本程序演示线程同步-读写锁。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>

pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER;   // 声明读写锁并初始化。

void *thmain(void *arg);    // 线程主函数。

void handle(int sig);       // 信号15的处理函数。

int main(int argc,char *argv[])
{
  signal(15,handle);       // 设置信号15的处理函数。

  pthread_t thid1,thid2,thid3;

  // 创建线程。
  if (pthread_create(&thid1,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
sleep(1);
  if (pthread_create(&thid2,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
sleep(1);
  if (pthread_create(&thid3,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }

  // 等待子线程退出。
  pthread_join(thid1,NULL);  pthread_join(thid2,NULL);  pthread_join(thid3,NULL);  

  pthread_rwlock_destroy(&rwlock);  // 销毁锁。
}

void *thmain(void *arg)    // 线程主函数。
{
  for (int ii=0;ii<100;ii++)
  {
    printf("线程%lu开始申请读锁...\n",pthread_self());
    pthread_rwlock_rdlock(&rwlock);    // 加锁。
    printf("线程%lu开始申请读锁成功。\n\n",pthread_self());
    sleep(5);
    pthread_rwlock_unlock(&rwlock);    // 解锁。
    printf("线程%lu已释放读锁。\n\n",pthread_self());

    if (ii==3) sleep(8);
  }
}

void handle(int sig)       // 信号15的处理函数。
{
  printf("开始申请写锁...\n");
  pthread_rwlock_wrlock(&rwlock);    // 加锁。
  printf("申请写锁成功。\n\n");
  sleep(10);
  pthread_rwlock_unlock(&rwlock);    // 解锁。
  printf("写锁已释放。\n\n");
}

条件变量
  1. 条件变量和互斥锁一起使用。实现生产者消费者模型,还可以通知功能。
    条件变量

api:

pthread_cond_t cond;// 定义条件变量
int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex)
int pthread_cond_signal(pthread_cond_t *__cond)
int pthread_cond_destroy(pthread_cond_t *__cond)

demo:

pthread_cond_t cond;// 定义条件变量
pthread_mutex_t mutex;
int max = 0;
void* arg_main1(void* arg) {
    while(1) {
            printf("线程%lu开始等待条件信号...\n",pthread_self());
            pthread_cond_wait(&cond,&mutex);    // 等待条件信号。
            printf("线程%lu等待条件信号成功。\n\n",pthread_self());
    }
}
void func(int sig) {
    printf("发送条件信号...\n");
     pthread_cond_signal(&cond);
}

int main()
{
    signal(15,func);

    pthread_cond_init(&cond,NULL);
    pthread_mutex_init(&mutex,NULL);

    pthread_t pid1,pid2;
    pthread_create(&pid1,NULL,&arg_main1,NULL);
    pthread_create(&pid2,NULL,&arg_main1,NULL);

    pthread_join(pid1,NULL);
    pthread_join(pid2,NULL);
    

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);
    return 0;
}
信号量

线程的信号量不能用在进程中。

api



// 本程序演示线程同步-信号量。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

int var;

sem_t sem;      // 声明信号量。

void *thmain(void *arg);    // 线程主函数。

int main(int argc,char *argv[])
{
  sem_init(&sem,0,1);   // 初始化信号量。

  pthread_t thid1,thid2;

  // 创建线程。
  if (pthread_create(&thid1,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
  if (pthread_create(&thid2,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }

  // 等待子线程退出。
  printf("join...\n");
  pthread_join(thid1,NULL);  
  pthread_join(thid2,NULL);  
  printf("join ok.\n");

  printf("var=%d\n",var);

  sem_destroy(&sem);  // 销毁信号量。
}

void *thmain(void *arg)    // 线程主函数。
{
  for (int ii=0;ii<1000000;ii++)
  {
    sem_wait(&sem);    // 加锁。
    var++;
    sem_post(&sem);  // 解锁。
  }
}

互斥锁的细节

互斥锁的细节

posted @ 2022-04-23 22:37  季以  阅读(57)  评论(0)    收藏  举报