Threads 的基本使用方法

POSIX Threads

1.1      Thread基本要素

ž   线程操作包括创、终止、同步(joins,blocking)、调度、数据管理、过程交互。

ž   一个线程不维持一个已创建线程列表,不知道哪些线程已经创建。

ž   在一个进程的所有线程共享相同的地址空间。

ž   同一个进程的线程共享:Process instructions,Most data,open files,signals and handlers,current working directory,user and group id

ž   每个线程拥有不同的Thread ID,set of registers,stack pointer,stack for local variables,return addresses,signal mask,priority, return value(errno)

ž   Pthreads函数返回0表示成功。

1.2      Thread 创建和终止

Examplepthread1.c

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

void *print_message_function( void *ptr );

main()
{
     pthread_t thread1, thread2;
     const char *message1 = "Thread 1";
     const char *message2 = "Thread 2";
     int  iret1, iret2;

    /*创建两个独立的线程,并且都执行同一个函数 */
     iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
     iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);
     /*等待线程1和线程2结束*/
     pthread_join( thread1, NULL);
     pthread_join( thread2, NULL); 

     printf("Thread 1 returns: %d\n",iret1);
     printf("Thread 2 returns: %d\n",iret2);
     exit(0);
}

void *print_message_function( void *ptr )
{
     char *message;
     message = (char *) ptr;
     printf("%s \n", message);
}

 

编译:gcc –o  pthread1  –lpthread  pthread1.c

运行:./pthread1

结果:Thread 1
Thread 2
Thread 1 returns: 0
Thread 2 returns: 0

ž   线程的终止可以显示的调用pthread_exit或让回调函数返回,或调用exit来终止进程以及包括的所有线程。

ž   函数调用:pthread_create创建新的线程

  int  pthread_create(pthread_t *thread,

                  const pthread_attr_t * attr,

                  void * (*start_routine)(void *),

                  void *arg);

参数:

thread:返回线程的ID,类型为unsigned long int,定义在bits/pthreadtypes.h中。

attr    :如果使用默认的属性则设为NULL,否则需要定义结构pthread_attr_tbits/pthreadtypes.h)的成员。属性值见Man

void * (*start_routine)指向线程的入口函数,包含一个指向void型的指针。

*arg:函数的参数,传递多参数时,用指向结构体的指针。

ž   函数调用:pthread_join等待另外一个线程终止

  int  pthread_join(pthread_t  th,

                void **thread_return);

参数:

     th:线程ID  

 thread_return:如果该值不为空,返回值将存储在thread_return指向的地址。

ž   函数调用:pthread_exit终止调用的线程

 

void  pthread_exit(void *retval);

参数:retval:线程的返回值。该变量不能是局部变量。

该函数将kill一个线程。

注明:对于C,采用下面的方式传入口函数。

void print_message_function( void *ptr );
...
...
iret1 = pthread_create( &thread1, NULL, (void*)&print_message_function, (void*) message1);
...
...

1.3      Thread 同步

P_thread库提供了三种线程同步机制:mutexes(互斥锁)joins(让一个线程等待另外一个线程结束)、condition variables (条件变量,类型为pthread_cond_t)

Mutexes

主要用来保护内存数据的一致性以及防止资源竞争,当多个线程同时操作同一块内存中的数据时,将导致数据不一致。Mutexes只能在单个进程中的多个线程中使用,不能在不同的进程中使用,但是semaphores可以在不同的进程中使用。

无锁

 int counter = 0;

void functionC()

{

counter++;

}

 

有锁

/*变量和锁的范围是相同的*/

/*变量和锁的范围是相同的*/
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALZER;
int counter = 0;
void function()
{
pthread_mutex_lock(&mutex1);
counter++;
pthread_mutex_unlock(&mutex1);
}


 

Example:mutex1.c

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

void *functionC();
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;//锁的初始化
int  counter = 0;

main()
{
   int rc1, rc2;
   pthread_t thread1, thread2;
   if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) )
   {
      printf("Thread creation failed: %d\n", rc1);
   }

   if( (rc2=pthread_create( &thread2, NULL, &functionC, NULL)) )
   {
      printf("Thread creation failed: %d\n", rc2);
   }

   pthread_join( thread1, NULL);
   pthread_join( thread2, NULL); 

   exit(0);
}

void *functionC()
{
   pthread_mutex_lock( &mutex1 );
   counter++;
   printf("Counter value: %d\n",counter);
   pthread_mutex_unlock( &mutex1 );
}


 

编译:gcc –o  mutex1  –lpthread  mutex1.c

运行结果:

Counter value: 1
Counter value: 2
 
example :join1.c
include <stdio.h>
#include <pthread.h>

#define NTHREADS 10
void *thread_function(void *);
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int  counter = 0;

main()
{
   pthread_t thread_id[NTHREADS];
   int i, j;

   for(i=0; i < NTHREADS; i++)
   {
      pthread_create( &thread_id[i], NULL, thread_function, NULL );
   }

   for(j=0; j < NTHREADS; j++)
   {
      pthread_join( thread_id[j], NULL); 
   }
  
   /* 等所有的线程都执行结束 再打印*/

   printf("Final counter value: %d\n", counter);
}

void *thread_function(void *dummyPtr)
{
   printf("Thread number %ld\n", pthread_self());
   pthread_mutex_lock( &mutex1 );
   counter++;
   pthread_mutex_unlock( &mutex1 );
}

编译:cc -pthread join1.c or cc -lpthread join1.c
运行结果:
Thread number 1026
Thread number 2051
Thread number 3076
Thread number 4101
Thread number 5126
Thread number 6151
Thread number 7176
Thread number 8201
Thread number 9226
Thread number 10251
Final counter value: 10

条件变量pthread_cond_t

条件变量可以让线程中止执行,并且让出CPU直到条件变量为真。条件变量要和锁(没有规定是什么锁)一起使用,防止出现临界资源竞争。

Example code:cond.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

//初始化锁和条件变量
pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;

void *functionCount1();
void *functionCount2();
int  count = 0;
#define COUNT_DONE  10
#define COUNT_HALT1  3
#define COUNT_HALT2  6

main()
{
   pthread_t thread1, thread2;
   //创建两个线程并设置入口函数
   pthread_create( &thread1, NULL, &functionCount1, NULL);
   pthread_create( &thread2, NULL, &functionCount2, NULL);
   //等待两个线程结束
   pthread_join( thread1, NULL);
   pthread_join( thread2, NULL);

   printf("Final count: %d\n",count);

   exit(0);
}

// 根据函数functionCount2()设置的条件变量,来写数字1-3和8-10

void *functionCount1()
{
   for(;;)
   {
      // Lock mutex and then wait for signal to relase mutex
      pthread_mutex_lock( &count_mutex );

     
      //解锁count_mutex,并等条件变量的发生
      pthread_cond_wait( &condition_var, &count_mutex );
      count++;
      printf("Counter value functionCount1: %d\n",count);

      pthread_mutex_unlock( &count_mutex );

      if(count >= COUNT_DONE) return(NULL);
    }
}

// 写数字4-7

void *functionCount2()
{
    for(;;)
    {
       pthread_mutex_lock( &count_mutex );

       if( count < COUNT_HALT1 || count > COUNT_HALT2 )
       {
         
          //条件满足,给等待的线程发信号,并且释放锁
          pthread_cond_signal( &condition_var );
       }
       else
       {
          count++;
          printf("Counter value functionCount2: %d\n",count);
       }

       pthread_mutex_unlock( &count_mutex );

       if(count >= COUNT_DONE) return(NULL);
    }

}

编译:cc -pthread cond1.c or cc -lpthread cond1.c
运行结果:
Counter value functionCount1: 1
Counter value functionCount1: 2
Counter value functionCount1: 3
Counter value functionCount2: 4
Counter value functionCount2: 5
Counter value functionCount2: 6
Counter value functionCount2: 7
Counter value functionCount1: 8
Counter value functionCount1: 9
Counter value functionCount1: 10
Final count: 10

线程陷阱

1.       条件竞争:在多线程环境中,可能代码的执行顺序不是按照书写的顺序执行,由于操作系统的调度,各个线程的执行顺序不同,并且各个线程执行的速度也不同,会导致不可预期的结果。

2.       线程安全代码:对于静态变量和全局变量的访问必须要加锁,禁止使用不可重入的函数。如strtok函数,要使用线程安全的函数strtok_r.

3.       线程死锁:当使用两把或更多把锁的时候要防止死锁。可以使用下面的方法来防止死锁。

...
pthread_mutex_lock(&mutex_1);
while ( pthread_mutex_trylock(&mutex_2) )  /* Test if already locked   */
{
   pthread_mutex_unlock(&mutex_1);  /* Free resource to avoid deadlock */
   ...
   /* stall here   */
   ...
   pthread_mutex_lock(&mutex_1);
}
count++;
pthread_mutex_unlock(&mutex_1);
pthread_mutex_unlock(&mutex_2);
...

### POSIX Threads (pthreads) 的基本概念 在编程领域中,POSIX Threads(简称 pthreads)是一种用于实现多线程程序的标准 API。通过使用 `pthread_create()` 创建新线程,可以并行运行多个任务[^1]。 #### 线程同步机制 为了确保线程之间的安全通信和资源共享,`pthread_join()` 是一种常用的同步方法。它允许主线程等待某个特定线程完成后再继续执行其他操作。这种设计有助于管理资源释放以及收集子线程的结果。 ```c #include <pthread.h> #include <stdio.h> void* thread_function(void* arg) { printf("Thread is running\n"); return NULL; } int main() { pthread_t thread_id; // Create a new thread if (pthread_create(&thread_id, NULL, thread_function, NULL)) { fprintf(stderr, "Error creating thread\n"); return 1; } // Wait for the thread to finish pthread_join(thread_id, NULL); printf("Thread joined successfully\n"); return 0; } ``` 上述代码展示了如何创建一个新的线程并通过 `pthread_join()` 来等待该线程结束。 --- ### 协程与线程的区别及其应用场景 尽管线程能够提供高效的并发能力,但在某些场景下仍然存在不足之处。例如,在 I/O 密集型应用中,频繁的上下文切换可能导致性能下降。此时引入了 **协程** 技术来解决这一问题[^2]。 协程本质上是一个轻量级的任务单元,由开发者手动控制其暂停与恢复行为。相比于操作系统级别的线程调度,协程可以在单一线程内部高效地模拟出大量独立运行的小任务。这种方式特别适合处理异步事件驱动模型下的高并发需求。 以下是 Python 中基于 asyncio 库的一个简单示例: ```python import asyncio async def coroutine_task(): await asyncio.sleep(1) print("Coroutine task completed") async def main(): tasks = [coroutine_task(), coroutine_task()] await asyncio.gather(*tasks) if __name__ == "__main__": asyncio.run(main()) ``` 此脚本定义了一个简单的协程函数,并利用 `await` 关键字实现了非阻塞式的延迟逻辑。 --- ### 彩票调度算法简介 除了传统的 FIFO 和优先级队列之外,还有一种更加灵活公平的调度策略——彩票调度法(Lottery Scheduling)。在这种方案里,每个进程都会被分配一定数量的虚拟 “抽奖券”,每当需要做出一次调度决策时便随机抽取一张作为获胜者授予相应计算时间片奖励[^3]。 这种方法不仅保留了传统轮询方式的优点,同时还具备动态调整权重的能力从而更好地适应复杂工作负载环境变化的需求特点。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值