Linux下的多线程编程

Linux下提供了多种方式来处理线程同步,常用的是互斥锁,条件变量,信号量和读写锁。

进程是一个程序的一个实例,拥有自己独立的各种段(数据段,代码段等等),每次创建一个进程需要从操作系统分配这些资源给他,消耗一定的时间,在linux下C语言创建一个进程使用fork()函数;
线程是一个轻量级的进程,除了自己少数的资源,不用用其他资源,且一个进程可以创建多个线程,这些线程共享进程的资源,创建线程的时间要比创建进程少很多,(几十分之一),从函数角度是使用pthread_create()创建。使用线程处理文件I/O或者socket处理都是非常有优势的,将一个大人物分解成若干个小任务,每个线程处理一个任务,线程之间切换不需要花很多时间,而且线程之间数据交换很方便,共享存储区。

C语言中多线程的函数

创建线程

int pthread_create(pthread_t * tid, const pthread_attr_t * attr, void * ( * func) (void * ), void * arg);
其返回值是一个整数,若创建进程成功返回0,否则,返回其他错误代码,也是正整数

 参数1:pthread_t *类型,是标示线程的id,一般是无符号整形,这里也可以是引用类型,目的是用于返回创建线程的ID

参数3:为线程所执行程序的地址

其余2个参数可以设置为NULL

结束线程

void pthread_exit (void *status);
参数是指针类型,用于存储线程结束后返回状态。

线程等待

int pthread_join (pthread_t tid, void ** status);
第一个参数表示要等待的进程的id;
第二参数表示要等待的进程的返回状态,是个二级指针。

多线程的同步与互斥

锁机制

多线程之间可能需要互斥的访问一些全局变量,这就需要互斥的来访问,这些需要共享访问的字段被称作是临界资源,访问临界资源的程序段称作是临界区
实现线程间的互斥与同步机制的是锁机制,下面是常用的锁机制的函数和类。

1.pthread_mutex_t mutex 锁对象
2.pthread_mutex_init(&mutex,NULL) 在主线程中初始化锁为解锁状态
3.pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER 编译时初始化锁位解锁状态
4.pthread_mutex_lock(&mutex)(阻塞加锁)访问临界区加锁操作
5.pthread_mutex_trylock( &mutex)(非阻塞加锁); pthread_mutex_lock() 类似,不同的是在锁已经被占据时返回 EBUSY 而不是挂起等待。
6.pthread_mutex_unlock(&mutex): 访问临界区解锁操作

不加锁的示例

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
 
int sharei = 0;
void increase_num(void);
 
int main()
{
  int ret;
  pthread_t thread1,thread2,thread3;
  ret = pthread_create(&thread1,NULL,(void *)&increase_num,NULL);
  ret = pthread_create(&thread2,NULL,(void *)&increase_num,NULL);
  ret = pthread_create(&thread3,NULL,(void *)&increase_num,NULL);
 
  pthread_join(thread1,NULL);
  pthread_join(thread2,NULL);
  pthread_join(thread3,NULL);
 
  printf("sharei = %d\n",sharei);
 
  return 0;
}
 
void increase_num(void)
{
  long i,tmp;
  for(i =0;i<=10000;++i)
  {
    tmp = sharei;
    tmp = tmp + 1;
    sharei = tmp;
  }
}

加锁的示例

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
 
int sharei = 0;
void increase_num(void);
// add mutex
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
int main()
{
  int ret;
  pthread_t thread1,thread2,thread3;
  ret = pthread_create(&thread1,NULL,(void *)&increase_num,NULL);
  ret = pthread_create(&thread2,NULL,(void *)&increase_num,NULL);
  ret = pthread_create(&thread3,NULL,(void *)&increase_num,NULL);
 
  pthread_join(thread1,NULL);
  pthread_join(thread2,NULL);
  pthread_join(thread3,NULL);
 
  printf("sharei = %d\n",sharei);
 
  return 0;
}
 
void increase_num(void)
{
  long i,tmp;
  for(i =0;i<=10000;++i)
  {
    // lock
    if(pthread_mutex_lock(&mutex) != 0)
    {
      perror("pthread_mutex_lock");
      exit(EXIT_FAILURE);
    }
    tmp = sharei;
    tmp = tmp + 1;
    sharei = tmp;
    // unlock
    if(pthread_mutex_unlock(&mutex) != 0)
    {
      perror("pthread_mutex_unlock");
      exit(EXIT_FAILURE);
    }
  }
}

信号量机制

锁机制使用是有限制的,锁只有两种状态,即加锁和解锁,对于互斥的访问一个全局变量,这样的方式还可以对付,但是要是对于其他的临界资源,比如说多台打印机等,这种方式显然不行了。
信号量机制在操作系统里面学习的比较熟悉了,信号量是一个整数计数器,其数值表示空闲临界资源的数量。
当有进程释放资源时,信号量增加,表示可用资源数增加;当有进程申请到资源时,信号量减少,表示可用资源数减少。这个时候可以把锁机制认为是0-1信号量。
关于信号量机制的函数。

int sem_init(sem_t * sem, int pshared, unsigned int value);初始化信号量

- 成功返回0,失败返回-1;
- 参数sem:表示指向信号结构的指针。
- 参数pshared:不是0 的时候该信号量在进程间共享,否则只能在当前进程的所有线程间共享。
- 参数value:信号量的初始值。

int sem_wait(sem_t *sem); 信号量减一操作,有线程申请资源

- 成功返回0,否则返回-1
- 参数sem:指向一个信号量的指针

int sem_post(sem_t *sem);信号量加一操作,有线程释放资源

- 成功返回0,否则返回-1
- 参数sem:指向一个信号量指针

int sem_destroy(sem_t *sem); 销毁信号量

- 成功返回0,否则返回-1
- 参数sem:指向一个信号量的指针。

信号量实例

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
 
#define MAXSIZE 10
 
int stack[MAXSIZE];
 
int size =0;
sem_t sem;
 
void privide_data(void)
{
  int i;
  for(i =0;i<MAXSIZE;++i)
  {
    stack[i] = i;
    sem_post(&sem);
  }
}
 
void handle_data(void)
{
  int i;
  while((i = size ++) <MAXSIZE)
  {
    sem_wait(&sem);
    printf("cross : %d X %d = %d \n",stack[i],stack[i],stack[i] * stack[i]);
    sleep(1);
  }
}
 
int main()
{
  pthread_t privider,handler;
  sem_init(&sem,0,0);
  pthread_create(&privider,NULL,(void *)&privide_data,NULL);
  pthread_create(&handler,NULL,(void *)&handle_data,NULL);
  pthread_join(privider,NULL);
  pthread_join(handler,NULL);
  sem_destroy(&sem);
 
  return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值