并行程序设计-Windows多线程编程-多核1

#include <windows.h>
#include <stdio.h>
const int gNumThreads = 4;
int gPi = 0;
CRITICAL_SECTION gCS;            //声明一个临界区对象
const int numThreads = 4;
const int numEnd = 1000;
int sum=0;

DWORD WINAPI threadFunction(LPVOID pArg)    //返回值进程id(dword类型)    参数类型 LPVOID
{
int myNum = *((int *)pArg);

printf("Hello Thread %d\n", myNum); 
int sum = 0;
for ( int i=myNum; i<=numEnd; i+=gNumThreads )  // use every gNumThreads-th step用于实现//各个线程的值
{
sum = sum + i;
}

EnterCriticalSection(&gCS);    //进入临界区
  gPi += sum;  // add partial to global final answer 用于实现求4个线程各sum的
LeaveCriticalSection(&gCS);//离开临界区
Sleep(3000);
return 0;
}

void main()
{
HANDLE threadHandles[gNumThreads];    //线程数组
int tNum[gNumThreads];                //用于传给线程的参数数组    参数个数是:gNumThreads
    printf("Computed value of Pi:\n");
InitializeCriticalSection(&gCS);            //临界区 gcs变量 的初始化

for ( int i=0; i<gNumThreads; ++i )
{
tNum[i] = i;
threadHandles[i] = CreateThread( NULL,            // Security attributes        线程创建函数(CreateThread)参数分别为  安全属性
                                 0,               // Stack size                  栈大小
                                 threadFunction,  // Thread function               传给线程的函数
                                 (LPVOID)&tNum[i],// Data for thread func()        传给线程的参数
                                 0,               // Thread start mode            线程开始时是否挂起
                                    //值为CREATE_SUSPENDED------------------创建一个挂起的线程,   
                                    //值为0---------------------------------表示创建后立即激活。 
                                 NULL);           // Returned thread ID            新线程的id会被传给这个参数所在的变量
}
//也可以等待信号量,事(函数原型见后面的图片waitformultipleobjects()函数)件 WaitForMultipleObjects(gNumThreads, //等待的线程数 threadHandles, //等待的线程数组 TRUE, //值为false:返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号 //如果同时有多个内核对象被触发,这个函数返回的只是其中序号最小的那个。

                          //值为TRUE:则等待所有信号量有效在往下执行。
//(FALSE 当有其中一个信号量有效时就向下执行)
//true表示所有的handles都必须激发,此函数才返回, //否则此函数数将在任何一个handle激发时就还回 INFINITE); //infinite 表示无穷等待 其它值如 5 表示在等待时间超过5后就返回,不在继续等待 DeleteCriticalSection(&gCS); //删除临界区 printf("sum(1..%d) = %d\n", numEnd, gPi); Sleep(3000); //程序睡觉三秒 } /*多线程编程 临界区,事件,信号量,互斥量。12011-09-03 16:11在进行多线程编程时,难免还要碰到两个问题,那就线程间的互斥与同步: 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。 线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步(下文统称为同步)。 线程间的同步方法大体可分为两类:用户模式和内核模式。顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。 用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。内核模式下的方法有:事件,信号量,互斥量。 下面我们来分别看一下这些方法: 原子操作(全局变量): #include "stdafx.h" #include "windows.h" #include "stdio.h" volatile int ThreadData = 1; void ThreadProcess() { for(int i=0; i<6; i++) { Sleep(1000); printf("Sub Thread Tick %5d!\n",(i+1)*1000); } ThreadData = 0; printf("Exit Sub Thread!\n"); } int _tmain(int argc, _TCHAR* argv[]) { HANDLE hThread; DWORD ThreadID; hThread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcess, NULL, 0, &ThreadID); while (ThreadData) { printf("Main Thread is waiting for Sub Thread!\n"); Sleep(600); } printf("Main Thread Finished! \n"); system("pause"); return 0; } 在上面的程序中,我利用了全局变量ThreadData来进行线程间的同步,当子线程结束时改变该值,而父线程则循环判断该值来确认子线程是否已经结束,当子线程结束时,父线程才继续进行下面的操作。 临界区(Critical Section) 保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。 临界区包含两个操作原语: EnterCriticalSection() 进入临界区 LeaveCriticalSection() 离开临界区 EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。 互斥量(Mutex) 互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。互斥量比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。   互斥量包含的几个操作原语:   CreateMutex() 创建一个互斥量   OpenMutex() 打开一个互斥量   ReleaseMutex() 释放互斥量   WaitForMultipleObjects() 等待互斥量对象 */ /*Windows Via C/C++:线程的睡眠和切换2010-03-30 21:08 睡眠:Sleep 线程可以调用Sleep函数使其在指定时间内不被调度: VOID Sleep(DWORD dwMilliseconds); Sleep调用会挂起当前线程,dwMilliseconds毫秒之后再将其恢复为可调度的。Sleep函数有以下几点值得注意: Sleep调用会导致当前线程放弃其剩余的时间片 Sleep调用时,系统挂起当前线程的时长大约是dwMilliseconds毫秒——比如,当dwMilliseconds设置为100时,在大多数情况下,当前线程睡眠的时长并不会是100ms,可能是几百毫秒、几秒、几分钟甚至更长。因为Windows并不是一个实时系统,所以dwMilliseconds只是一个建议值 为dwMilliseconds传递INFINITE会使当前线程永远睡眠,这通常没什么用处 为dwMilliseconds传递0时,当前线程会放弃剩余的时间片,系统会尝试调度优先级等于或高于当前线程 的可调度线程,如果没有找到这样的线程,系统将马上重新调度调用Sleep的线程 切换:SwitchToThread 当前线程可以调用SwitchToThread强迫操作系统调度另外的可调度线程(如果存在): BOOL SwitchToThread(); 当前线程调用SwitchToThread时,系统会检查是否存在可调度的线程处于“饥饿”状态,如果没有找到,SwitchToThread立刻返回,系统继续执行当前线程,否则系统将暂停当前线程并调度处于“饥饿”状态的线程(无论该线程的优先级大小),“饥饿”线程的调度时间大约是一个时间片,然后系统调度将恢复正常。 当线程A需要获得某资源,而该资源又被另一优先级较低的线程B占用时,A可以调用SwitchToThread迫使操作系统调度低先级的进程,以期待B释放被占用的资源。当没有其它线程可调度时,SwitchToThread返回FALSE,否则返回一个非0值。 SwitchToThread函数和Sleep(0)调用类似,不同之处在于SwitchToThread允许系统调度优先级低于当前线程的可调度线程,但Sleep(0)只允许调度优先级不低于当前线程的可调度线程。 */

资源下载:http://pan.baidu.com/share/link?shareid=161909&uk=1678594189

 

 

posted @ 2012-12-10 13:26  xjx_user  阅读(925)  评论(0编辑  收藏  举报