编写一个多线程程序,使得3个线程同时运行。

编写一个多线程程序,使得3个线程同时运行。,第1张

才给5分啊~~~~~~难怪大家懒得做。我就贴一下读写者问题的多线程程序吧,希望对你有帮助。(好像是2个线程,太久了懒得看)

#include "windows.h"

#include <conio.h>

#include <stdlib.h>

#include <fstream.h>

#include <io.h>

#include <string.h>

#include <stdio.h>

#define READER 'R' //读者

#define WRITER 'W' //写者

#define INTE_PER_SEC 1000 //每秒时钟中断次数

#define MAX_THREAD_NUM 64 //最大线程数目

#define MAX_FILE_NUM 32 //最大数据文件数目

#define MAX_STR_LEN 32 //字符串长度

int readcount=0 //读者数目 (属临界资源,需以互斥方式访问)

int writecount=0 //写者数目 (属临界资源,需以互斥方式访问)

//定义3个临界资源

CRITICAL_SECTION RP_Write//临界区控制变量 (用于读者优先)

CRITICAL_SECTION cs_Write //临界区控制变量 (用于写者优先)

CRITICAL_SECTION cs_Read //临界区控制变量 (用于写者优先)

//定义线程及其 *** 作行为信息结构

struct ThreadInfo

{

int serial//线程序号

char entity //线程类别(是读者还是写者)

double delay //线程延迟

double persist //线程读写 *** 作的持续时间

}

// 读者优先――读者线程

void RP_ReaderThread(void *p) //p: 读者线程信息

{

//互斥变量

HANDLE h_Mutex

h_Mutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount")

//从参数中获得信息

DWORD wait_for_mutex //等待互斥变量所有权

DWORD m_delay //延迟时间

DWORD m_persist//读文件持续时间

int m_serial //线程序号

m_serial = ((ThreadInfo*)(p))->serial

m_delay = (DWORD)((ThreadInfo*)(p))->delay*INTE_PER_SEC

m_persist = (DWORD)((ThreadInfo*)(p))->persist*INTE_PER_SEC

Sleep(m_delay) //延迟等待

//输出读进程已发出读请求的提示信息

printf ("Reader thread %d sends the reading require.\n", m_serial)

//等待互斥信号,保证对readcount的互斥访问

wait_for_mutex = WaitForSingleObject(h_Mutex,-1)

readcount++

if (readcount==1) //第一个读者,等待临界区资源

EnterCriticalSection(&RP_Write)

ReleaseMutex(h_Mutex) //释放互斥信号

//输出读进程I 正在临界区中读 *** 作的提示信息

printf("Reader thread %d begins to read file.\n", m_serial)

Sleep(m_persist)

//退出线程

printf("Reader thread %d finished reading file. \n",m_serial)

//等待互斥信号,保证对readcount的互斥访问

wait_for_mutex = WaitForSingleObject(h_Mutex,-1)

readcount--

if (readcount==0) LeaveCriticalSection(&RP_Write)

ReleaseMutex(h_Mutex) //释放互斥信号

}

// 读者优先――写者线程

void RP_WriterThread(void *p) //p: 写者线程信息

{

DWORD m_delay //延迟时间

DWORD m_persist//读文件持续时间

int m_serial //线程序号

//从参数中获取信息m_serial, m_delay, m_persist ,

m_serial = ((ThreadInfo*)(p))->serial

m_delay = (DWORD)((ThreadInfo*)(p))->delay*INTE_PER_SEC

m_persist = (DWORD)((ThreadInfo*)(p))->persist*INTE_PER_SEC

//延迟等待m_delay秒;

Sleep(m_delay)

//输出信息"写线程 %d 发出写请求;

printf ("Writer thread %d sends the writing require.\n", m_serial)

//等待临界资源

EnterCriticalSection(&RP_Write)

//输出正在临界区执行写 *** 作的提示信息

//在临界区中写 *** 作,至少持续m_persist秒钟

printf("Writer thread %d begins to write file.\n", m_serial)

Sleep(m_persist)

printf("Writer thread %d finished writing file. \n",m_serial)

//释放临界资源

LeaveCriticalSection(&RP_Write)

}

// 读者优先――处理函数

void ReaderPriority(char *file) //file: 文件名

{

DWORD n_thread=0 //保存线程数目变量

DWORD thread_ID //线程ID

DWORD wait_for_all //保存――等待所有线程结束的返回值――的变量

HANDLE h_Thread[MAX_THREAD_NUM]

ThreadInfo thread_info[MAX_THREAD_NUM]

HANDLE h_Mutex=CreateMutex(NULL,FALSE,"mutex_for_readcount")

readcount=0

InitializeCriticalSection(&RP_Write) //初始化临界区

ifstream inFile

inFile.open(file)

printf("Reader Priority :\n\n")

while (inFile) { //读入每个读者、写者的信息

inFile>>thread_info[n_thread].serial

inFile>>thread_info[n_thread].entity

inFile>>thread_info[n_thread].delay

inFile>>thread_info[n_thread].persist

inFile.get()

n_thread++

}

n_thread-- //modify

for(int j=0j<(int)(n_thread)j++){

cout<<"threadinfo["<<j<<"]="<<thread_info[j].serial<<","<<thread_info[j].entity

<<","<<thread_info[j].delay<<","<<thread_info[j].persist<<endl

}

for(int i=0i<(int)(n_thread)i++){

//创建一个不被子进程继承的,使用默认大小堆栈的线程

if( thread_info[i].entity ==READER || thread_info[i].entity=='r')

h_Thread[i] = CreateThread(NULL, 0,

(LPTHREAD_START_ROUTINE)(RP_ReaderThread),

&thread_info[i],0,&thread_ID)

// thread_info[i]籍此传递给被创建线程,

// 创建标志=0, 表示线程被创建后立即执行 (其它:CREATE_SUSPEND)

//thread_ID 存放放回的线程ID标识, 可不用

else

h_Thread[i]=CreateThread(NULL, 0,

(LPTHREAD_START_ROUTINE)(RP_WriterThread),

&thread_info[i],0,&thread_ID)

}

//等待所有的线程结束

wait_for_all = WaitForMultipleObjects(n_thread, h_Thread, TRUE, -1)

printf("All reader and writer have finished operating. \n")

}

// 写者优先――读者线程

void WP_ReaderThread(void *p) //p: 读者线程信息

{

DWORD m_delay //延迟时间

DWORD m_persist//读文件持续时间

int m_serial //线程序号

m_serial = ((ThreadInfo*)(p))->serial

m_delay = (DWORD)((ThreadInfo*)(p))->delay*INTE_PER_SEC

m_persist = (DWORD)((ThreadInfo*)(p))->persist*INTE_PER_SEC

Sleep(m_delay)

printf ("Reader thread %d sends the reading require.\n", m_serial)

//延迟等待

//从参数中获取信息m_serial, m_delay, m_persist ,

//延迟等待m_delay秒;

//输出信息"读线程 %d 发出读请求的提示信息;

//打开(获取)两个互斥变量

HANDLE h_Mutex1, h_Mutex2

h_Mutex1=OpenMutex(MUTEX_ALL_ACCESS, FALSE, "mutex_for_writecount1")

/*由于写者优先,即使临界区中已有读者,也不能马上进入,

要等到没有等待写者(在写进程中,当无等待写者释放读者临界区所有权cs_Read)

因此,这里需要一个互斥信号量附加控制读者进入过程,这在读者优先算法中是不需要的。*/

DWORD wait_for_mutex1=WaitForSingleObject(h_Mutex1,-1)

EnterCriticalSection(&cs_Read)

// 用h_mutex2控制对readcount的访问

h_Mutex2 = OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount2")

DWORD wait_for_mutex2 = WaitForSingleObject(h_Mutex2,-1)

readcount++

if ( readcount==1) //第一个读者要等待写者写完

EnterCriticalSection(&cs_Write)

ReleaseMutex(h_Mutex2)

LeaveCriticalSection(&cs_Read)//让其它读者可进入临界区

ReleaseMutex(h_Mutex1)

//输出某读者进程在临界区中读的信息;

//在临界区中读 *** 作,至少持续m_persist秒钟

//输出某读者进程退出临界区的信息;

printf("Reader thread %d begins to read file.\n", m_serial)

Sleep(m_persist)

//退出线程

printf("Reader thread %d finished reading file. \n",m_serial)

wait_for_mutex2 = WaitForSingleObject(h_Mutex2,-1)

readcount--

if ( readcount==0) //最后一个读者,要唤醒写者

LeaveCriticalSection(&cs_Write)

ReleaseMutex(h_Mutex2)

}

// 写者优先――写者线程

void WP_WriterThread(void *p) //p: 写者线程信息

{

DWORD m_delay //延迟时间

DWORD m_persist//读文件持续时间

int m_serial //线程序号

//从参数中获取信息m_serial, m_delay, m_persist ,

m_serial = ((ThreadInfo*)(p))->serial

m_delay = (DWORD)((ThreadInfo*)(p))->delay*INTE_PER_SEC

m_persist = (DWORD)((ThreadInfo*)(p))->persist*INTE_PER_SEC

//延迟等待m_delay秒;

Sleep(m_delay)

//输出信息"写线程 %d 发出写请求;

printf ("Writer thread %d sends the writing require.\n", m_serial)

//打开(获取)两个互斥变量h_Mutex3

HANDLE h_Mutex3

h_Mutex3 = OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_writecount3")

DWORD wait_for_mutex3 = WaitForSingleObject(h_Mutex3,-1)

writecount++

if (writecount==1) //第一个等待写者,等待读者读完

EnterCriticalSection(&cs_Read)

ReleaseMutex(h_Mutex3)

EnterCriticalSection(&cs_Write)

//进入写着临界区

//输出某写者进程在临界区中写的信息;

//至少持续m_persist秒钟

//输出某写者进程退出临界区的信息;

printf("Writer thread %d begins to write file.\n", m_serial)

Sleep(m_persist)

printf("Writer thread %d finished writing file. \n",m_serial)

LeaveCriticalSection(&cs_Write) //写者离开临界区

wait_for_mutex3 = WaitForSingleObject(h_Mutex3,-1)

writecount--

if (writecount==0) //无其它等待写者,唤醒第一个读者

LeaveCriticalSection(&cs_Read)

ReleaseMutex(h_Mutex3)

}

// 写者优先――处理函数

void WriterPriority(char *file) //file: 文件名

{

DWORD n_thread=0, thread_ID, wait_for_all

HANDLE h_Mutex1=CreateMutex(NULL,FALSE,"mutex_for_writecount1")

HANDLE h_Mutex2=CreateMutex(NULL,FALSE,"mutex_for_readcount2")

HANDLE h_Mutex3=CreateMutex(NULL,FALSE,"mutex_for_writecount3")

//用CreateMutex创建3个互斥信号量句柄h_mutex1,h_mutex2, h_mutex3

//从数据文件读入信息,创建指定数目的读写进程

//读进程处理函数 WP_ReaderThread, 写进程处理函数WP_writerThread

HANDLE h_Thread[MAX_THREAD_NUM]

ThreadInfo thread_info[MAX_THREAD_NUM]

writecount=0

readcount=0

InitializeCriticalSection(&cs_Write)

InitializeCriticalSection(&cs_Read)

//初始化临界区

ifstream inFile

inFile.open(file)

printf("Write Priority :\n\n")

while (inFile) { //读入每个读者、写者的信息

inFile>>thread_info[n_thread].serial

inFile>>thread_info[n_thread].entity

inFile>>thread_info[n_thread].delay

inFile>>thread_info[n_thread].persist

inFile.get()

n_thread++

}

n_thread--

for(int j=0j<(int)(n_thread)j++){

cout<<"threadinfo["<<j<<"]="<<thread_info[j].serial<<","<<thread_info[j].entity

<<","<<thread_info[j].delay<<","<<thread_info[j].persist<<endl

}

for(int i=0i<(int)(n_thread)i++) {

//创建一个不被子进程继承的,使用默认大小堆栈的线程

if( thread_info[i].entity ==READER || thread_info[i].entity=='r' )

h_Thread[i] = CreateThread(NULL, 0,

(LPTHREAD_START_ROUTINE)(WP_ReaderThread),

&thread_info[i],0,&thread_ID)

// thread_info[i]籍此传递给被创建线程,

// 创建标志=0, 表示线程被创建后立即执行 (其它:CREATE_SUSPEND)

//thread_ID 存放放回的线程ID标识, 可不用

else

h_Thread[i]=CreateThread(NULL, 0,

(LPTHREAD_START_ROUTINE)(WP_WriterThread),

&thread_info[i],0,&thread_ID)

}

//等待所有的线程结束

wait_for_all = WaitForMultipleObjects(n_thread, h_Thread, TRUE, -1)

printf("All reader and writer have finished operating. \n")

}

///////////////////////////////////////////////////////////

///主函数

int main(int argc, char** argv)

{

char ch

while (true)

{

//打印显示信息

printf("***************************************\n")

printf("1. Reader Priority \n")

printf("2. Writer Priority \n")

printf("3. Exit \n")

printf("***************************************\n")

printf("Enter your choice(1,2,or 3): \n")

do {

ch = (char)_getch()

} while (ch != '1' &&ch != '2' &&ch!='3')

system("cls")

if(ch=='3') return 0

else if(ch=='1') ReaderPriority("thread.dat")

else if(ch=='2') WriterPriority("thread.dat")

//结束

printf("\nPress any key to continute:")

_getch()

system("cls")

}

return 1

}

当多个线程访问一个独占性共享资源时,可以使用“临界区”对象。任一时刻只有一个线程可以拥有临界区对象,拥有临界区的线程可以访问被保护起来的资源或代码段,其他希望进入临界区的线程将被挂起等待,直到拥有临界区的线程放弃临界区时为止,这样就保证了不会在同一时刻出现多个线程访问共享资源。

CCriticalSection类的用法非常简单,步骤如下:

 

定义CCriticalSection类的一个全局对象(以使各个线程均能访问),如CCriticalSection critical_section;

在访问需要保护的资源或代码之前,调用CCriticalSection类的成员Lock()获得临界区对象: critical_section.Lock()

在线程中调用该函数来使线程获得它所请求的临界区。如果此时没有其它线程占有临界区对象,则调用Lock()的线程获得临界区;否则,线程将被挂起,并放入到一个系统队列中等待,直到当前拥有临界区的线程释放了临界区时为止。

访问临界区完毕后,使用CCriticalSection的成员函数Unlock()来释放临界区:critical_section.Unlock()

再通俗一点讲,就是线程A执行到critical_section.Lock()语句时,如果其它线程(B)正在执行critical_section.Lock()语句后且critical_section. Unlock()语句前的语句时,线程A就会等待,直到线程B执行完critical_section. Unlock()语句,线程A才会继续执行。

呵呵,当初我学多线程时也遇到过这样的问题,也是输出的结果每次都不一样。后来我找到原因了---都是多核惹得祸。

我猜你的电脑应该也是多核的。单核的cpu在处理多线程时每次只能执行一跳指令,也就是说无论你的程序有多少个线程,每一时刻执行的也只是一个线程里的代码,cpu会轮流给每个线程分配时间片,时间片分配到哪个线程头上,哪个线程里的代码就执行。但是多核cpu就不一样了,他可以同时执行多个线程里的代码,这才是真正的“多线程”。所以你那段程序,在单核的电脑上跑应该是没有问题的,但是在多核cpu的电脑上出现的结果就会有很大的随机性。

就你贴的那张图来说,左边的运行时恰好是这样的,首先cpu1执行你主线程里的代码 在终端输出Now another thread has been created. ID =,但是由于多个cpu是同时进行的,而这时cpu2已经开始执行ThreadProc里的代码,也要开始向终端输出字符,而你的屏幕只有一个,恰好这时cpu1的时间片被移走了,所以cpu2开始执行ThreadProc里的代码向屏幕上输出,直到打完I am from a thread 17后,恰好cpu2的时间片被移走了,这时cpu1接着向屏幕打dwThreadId的值,这就出现了4660.接着又是cpu2执行完ThreadProc中剩余的代码又打了几行。

右边的这个程序运行时,恰好就是cpu1执行主线程代码输出完后,cpu2再执行线程函数中代码,符合你的预期。

但是,关键问题在于,你无法预测每个cpu的时间片分配。所以,要得到你想要的输出结果就属于随机事件了。

对与多核cpu 上的程序同步问题,最好不要用信号量,互斥量,事件对象,因为它们都属于内核对象,都是对一个cpu而言的。其他的cpu根本不会理睬你设置的这些东西。另外你的WaitForSingleObject (hThread, INFINITE)也是在一个cpu里等待线程函数返回,对cpu2没有任何作用。

建议你用临界区(Critical Section)来实现多线程同步,因为临界区不是内核对象,他只是在进程内存中一块区域,无论有多少个cpu,任何时刻只能有一个线程访问这块内存区域,只需将你打印的部分放到临界区里就行了。

#include "stdafx.h"

#include <windows.h>

#include <iostream>

using namespace std

CRITICAL_SECTION g_cs

DWORD WINAPI ThreadProc(

LPVOID lpParameter // thread data

)

{

int i=0

while (i<20)

{

EnterCriticalSection(&g_cs)

cout<<"I am from a thread"<<" "<<i++<<endl

LeaveCriticalSection(&g_cs)

}

return 0

}

int main(int argc, char* argv[])

{

HANDLE hThread

DWORD dwThreadId

InitializeCriticalSection(&g_cs)

// 创建一个线程

hThread = ::CreateThread (

NULL, // 默认安全属性

NULL, // 默认堆栈大小

ThreadProc, // 线程入口地址(执行线程的函数)

NULL, // 传给函数的参数

0, // 指定线程立即运行

&dwThreadId)// 返回线程的ID号

EnterCriticalSection(&g_cs)

cout<<"Now another thread has been created. ID ="<<dwThreadId <<"\n"

LeaveCriticalSection(&g_cs)

// 等待新线程运行结束

::WaitForSingleObject (hThread, INFINITE)

::CloseHandle (hThread)

return 0

}

ps: kdzhy2008推荐的 侯捷 译的《win32多线程程序设计》确实是本好书,虽然是97年出版的,但是很多东西对现在还是很有启迪的。

希望对你能有所帮助,呵呵~~


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/8169131.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-14
下一篇2023-04-14

发表评论

登录后才能评论

评论列表(0条)

    保存