线程同步


c#下可以用ManualResetEvent类实现


ManualResetEvent通知一个或多个正在等待的线程已发生事件。 此类不能被继承。

构造函数

public ManualResetEvent(
bool initialState
)

initialState
类型:System.Boolean
如果为 true,则将初始状态设置为终止;如果为 false,则将初始状态设置为非终止。

如果 ManualResetEvent 的初始状态是终止状态(即,如果其通过为 initialState 传递true 创建),则等待 ManualResetEvent 的线程不阻塞。 如果初始状态为非终止状态,则线程调用 Set 方法后才不阻塞。

方法

Reset 将事件状态设置为非终止状态,导致线程阻止。 (继承自 EventWaitHandle。)
Set            将事件状态设置为终止状态,允许一个或多个等待线程继续。 (继承自 EventWaitHandle。)
WaitOne() 阻止当前线程,直到当前 WaitHandle 收到信号。

终止状态时WaitOne()允许线程访问下边的语句
非终止状态时WaitOne()阻塞线程,不允许线程访问下边的语句

下面是一个实现Http下载的例子

<span style="font-size:18px;">public class DownloadProcessor
{
    public ManualResetEvent allDone = new ManualResetEvent(false);
    const int BUFFER_SIZE = 1024;


    public byte[] Download(string url, DownloadProgressHandler progressCB)//下载函数
    {
        // 保证标志设置正确.<span style="white-space:pre">			</span>
        allDone.Reset();//执行到WaitOne后,下面的语句会阻塞


        //从命令行当中获取url.
        Uri httpPath = new Uri(url);


        //创建请求对象.
        WebRequest req = WebRequest.Create(httpPath);


        //创建状态对象.
        DownloadDetail detail = new DownloadDetail();


        //将请求放入状态对象以便能够被传递.
        detail.webRequest = req;


        //给回调函数赋值
        detail.ProgressCallback += progressCB;


        //声明异步请求.
        IAsyncResult r = (IAsyncResult)req.BeginGetResponse(new AsyncCallback(ResponseCallback), detail);


        //一直阻塞直到ManualResetEvent被置记号,即下载完毕时才继续向下执行


        allDone.WaitOne();


        //将下载的信息传递回去.


        if (detail.useBuffers)
            return detail.BufferFast;
        else
        {
            byte[] data = new byte[detail.BufferSlow.Count];
            for (int b = 0; b < detail.BufferSlow.Count; b++)
                data[b] = (byte)detail.BufferSlow[b];
            return data;
        }
    }


    private void ResponseCallback(IAsyncResult iar)
    {
        //从async中得到DownloadInfo对象
        DownloadDetail detail = (DownloadDetail)iar.AsyncState;


        //从RequestState中得到WebRequest.
        WebRequest webreq = detail.webRequest;


        //调用创建WebResponse对象的EndGetResponse
        WebResponse webresp = webreq.EndGetResponse(iar);


        //从头中找到数据尺寸.
        string strLength = webresp.Headers["Content-Length"];
        if (strLength != null)
        {
            detail.Length = Convert.ToInt32(strLength);
            detail.BufferFast = new byte[detail.Length];
        }
        else
        {
            detail.useBuffers = false;
            detail.BufferSlow = new System.Collections.ArrayList(BUFFER_SIZE);
        }


        //开始从response流中读取数据
        Stream ResponseStream = webresp.GetResponseStream();


        // 将response stream存储在RequestState当中异步地去读取流
        detail.responseStream = ResponseStream;


        //  将do.BufferRead传递给BeginRead.
        IAsyncResult iarRead = ResponseStream.BeginRead(detail.Read,
            0,
            BUFFER_SIZE,
            new AsyncCallback(ReadCallBack),
            detail);
    }


    private void ReadCallBack(IAsyncResult asyncResult)
    {
        //从AsyncResult得到DownloadInfo对象.
        DownloadDetail detail = (DownloadDetail)asyncResult.AsyncState;


        //回收在RespCallback中设置的ResponseStream.
        Stream responseStream = detail.responseStream;


        // 读info.BufferRead来验证是否包含数据.
        int bytesRead = responseStream.EndRead(asyncResult);
        if (bytesRead > 0)//数据没有读取完毕,则继续读取
        {
            if (detail.useBuffers)
            {
                System.Array.Copy(detail.Read, 0,
                    detail.BufferFast, detail.bytes,
                    bytesRead);
            }
            else
            {
                for (int b = 0; b < bytesRead; b++)
                    detail.BufferSlow.Add(detail.Read[b]);
            }
            detail.bytes += bytesRead;


            // 如果进程回调,则通知进度条
            if (detail.ProgressCallback != null)
                detail.ProgressCallback(detail.bytes, detail.Length);


            // 一直读数据直到responseStream.EndRead返回
            IAsyncResult ar = responseStream.BeginRead(
                detail.Read, 0, BUFFER_SIZE,
                new AsyncCallback(ReadCallBack), detail);
        }
        else
        {
            responseStream.Close();
            allDone.Set();//下载完毕,将事件状态设置为终止状态,WaitOne后面的语句可以执行
        }
        return;
    }
}</span>


win32下c++用CreateEvent

CreateEvent是一个Windows API函数。它用来创建或打开一个命名的或无名的事件对象。

HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性
BOOL bManualReset,// 复位方式
BOOL bInitialState,// 初始状态
LPCTSTR lpName // 对象名称
);


lpEventAttributes[输入]
一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。
bManualReset[输入]
指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当一个等待线程被释放以后,系统将会自动将事件状态复原为无信号状态。
bInitialState[输入]
指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。
lpName[输入]
指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。
如果lpName为NULL,将创建一个无名的事件对象。如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文件映射对象名称相同,函数将会失败,在GetLastError函数中将返回ERROR_INVALID_HANDLE。造成这种现象的原因是这些对象共享同一个命名空间。

返回值
如果函数调用成功,函数返回事件对象的句柄。如果对于命名的对象,在函数调用前已经被创建,函数将返回存在的事件对象的句柄,而且在GetLastError函数中返回ERROR_ALREADY_EXISTS。
如果函数失败,函数返回值为NULL,如果需要获得详细的错误信息,需要调用GetLastError。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值